More efficient looping? [closed] - c#

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
So I'm writing a simple struct to act like an Array of strings but with some handy operators and other functions that I've always wanted to see in strings. Specifically the method I'm working on right now is the / operator. The problem is, it won't add on any remainders at the end like I want it to.
What it's supposed to do, is take an array of strings, like {"Hello", "Test1", "Test2", "Goodbye", "More?", "Qwerty"} and, say I want to divide by 4, it should return { {"Hello", "Test1", "Test2", "Goodbye"}, {"More?", "Qwerty"} } but it doesn't.
The whole class (the method I want to improve is the / operator, but if you see anything else I can work on please point it out) (I know barely any of it is commented. Sorry about that, didn't expect anyone else to see this code aside from me.):
public struct StringCollection
{
private String[] value;
public StringCollection(params String[] s)
{
this.value = s;
}
public StringCollection(StringCollection current, String ad)
{
if (current.value == null) {
current.value = new String[0] { };
}
this.value = new String[current.value.Length+1];
for (int i=0; i<this.value.Length; i++)
{
try {
this.value[i] = current[i];
} catch {
break;
}
}
this.value[this.value.Length-1] = ad;
}
public StringCollection(StringCollection x, params StringCollection[] y)
{
this.value = x.value;
for (int j=0;j<y.Length;j++)
{
for (int i=0;i<y[j].value.Length;i++)
{
this += y[j][i];
}
}
}
public static StringCollection[] operator /(StringCollection x, int y)
{
StringCollection[] result = null;
if (((int)x.value.Length/y) == ((double)x.value.Length)/y)
result = new StringCollection[y];
else
result = new StringCollection[y+1];
for (int j=0;j<y;j++)
{
for (int i=0;i<((int)x.value.Length/y);i++)
{
result[j] += x.value[i+(int)((x.value.Length/y)*j)];
}
}
if (((int)x.value.Length/y) != ((double)x.value.Length)/y)
{
// This is the part that isn't working.
for (int i=0;i<(((int)x.value.Length/y)*result[0].value.Length)-x.value.Length;i++)
{
result[result.Length-1] += x.value[i+((result[0].value.Length)*result.Length-2)];
}
}
return result;
}
public String this[int index]
{
get {
return this.value[index];
}
set {
this.value[index] = value;
}
}
}
What it does is basically takes your array (single array) and splits it into a bunch of arrays that are the same size, then it adds on the remainder in a new array at the end.

Firstly your question isn't really related to loops at all, or at least loops are only addressed in your code. You should have titled this differently.
Secondly your array adding/removing could be improved; i.e. adding 1 to array size every time and removing 1 then re-copying the entire array every time is a time-sink.
Now onto your question, your code should basically look like this:
//Make your return array
int retLen = x.Length / y;
//Add space for the remainder
if(x.Length % y != 0)
retLen++;
var ret = new StringCollection[retLen];
//Reusing variables is a good way to save memory, but watch naming conventions as this can be confusing
retLen = 0;
var tempCollection = new StringCollection();
for (int i = 0; i < x.Length; i++)
{
tempCollection = new StringCollection(tempCollection, x[i]);
if(i % y == 0 || i == x.Length - 1)
{
ret[retLen++] = tempCollection;
tempCollection = new StringCollection();
retLen = 0;
}
}
return ret;
I really don't like that you don't have a Add function in this struct, just so we're clear. the tempCollection = new StringCollection(tempCollection, x[i]); is f$*kin' TERRIBLE when it comes to time CPU time to create all those new objects.
Pretty sure you'll need to tweak that to make sure all items are entered properly, but that was a first attempt, so ... meh o.O Figured since no one was actually going to answer you I'd take the time.
EDIT: Found a bug, forgot to set retLen back to 0 when adding to ret

Related

Current code to generate array filled with unique ints crashes

(this is a library)
The function GetUniqueInt is being called with (5, 5) as the variables.
Currently the code will stall unity to a complete halt, or crash my PC with a memory overflow error.
Does anyone have any ideas as to how I could prevent it from crashing or what is making it crash?
using UnityEngine;
namespace MajorSolution
{
public static class MajorMath
{
public static int[] GetUniqueInt(int intCount, int intLength)
{
int[] returnValue = new int[intCount];
int[] temp = new int[intLength];
for (int a = 0; a < intCount; a++)
{
string create = new string("create".ToCharArray());
switch (create)
{
case "create":
returnValue[a] = GetRandomInt(intCount);
goto case "check";
case "check":
bool alreadyTaken = false;
for (int c = 0; c < returnValue.Length - 1; c++)
{
if (returnValue[a] == returnValue[c])
{
// Already Taken!
alreadyTaken = true;
}
}
if (!alreadyTaken)
{
break;
}
else
{
goto case "create";
}
}
}
Debug.Log(returnValue);
return returnValue;
}
public static int GetRandomInt(int intCount)
{
int[] storage = new int[intCount];
int returnValue = 0;
for (int i = 0; i < intCount; i++)
{
storage[i] = (Mathf.FloorToInt(Random.Range(0, 9)) * (int)Mathf.Pow(10,i));
returnValue += storage[i];
}
return returnValue;
}
}
}
Edit I just realized I did not exactly answer the question of why it is bringing the PC to a halt because you have an infinite loop in the code.
The problem is occurring in the following lines of code, notice what is happening.
case "create":
returnValue[a] = GetRandomInt(intCount);
goto case "check";
In the above block of code you are generating a number and putting it in the returnValue array. Now you jump into your "check" block
case "check":
bool alreadyTaken = false;
for (int c = 0; c < returnValue.Length - 1; c++)
{
if (returnValue[a] == returnValue[c])
{
// Already Taken!
alreadyTaken = true;
}
}
In this block of code you are looping over the entire returnValue array including the value you just inserted in it. Basically you are looping over the array asking if a value that you just put in the array is in the array.
Without knowing exactly what you are trying to do with these methods, I will just make a simple fix suggestion with some minor cleanup
public static int[] GetUniqueInt(int count, int length)
{
var returnValue = new int[count];
var values = new HashSet<int>(); // Used to track what numbers we have generated
for (int i = 0; i < count; ++i)
{
// Generate the number and check to be sure we haven't seen it yet
var number = GetRandomInt(length);
while(values.Contains(number)) // This checks if the number we just generated exists in the HashSet of seen numbers
{
// We get here if the HashSet contains the number. If we have
// seen the number then we need to generate a different one
number = GetRandomInt(length);
}
// When we reach this point, it means that we have generated a new unique number
// Add the number to the return array and also add it to the list of seen numbers
returnValue[a] = number;
values.Add(number); // Adds the number to the HashSet
}
Debug.Log(returnValue);
return returnValue;
}
I did end up removing the using of intLength but from your posted code it was only used to declare a temp array which itself was never used. Based on that, I just removed it entirely.
Based on your comment I updated the fix to use intLength. I made one other minor change. I removed int from the variable names of count and length. Hungarian notation is a lot less common in C# code. Personally, I feel like the code is cleaner and easier to read without the Hungarian notation. The key is to use good variable names that express the intent or make it easier to follow. In this case count is the count (read total number) of numbers you want returned and length is the length of the number. You could consider maybe even renaming that to numberOfDigits to make it clearer that the idea is you are going to create a random number with that number of digits in it.

C# - HackerRank simpleArraySum

Now, I may get negative points because perhaps somewhere in vast internet there is already an answer to this but I tried to look for it and I simply couldnt find it.
The gist of the problem is that HackerRanks wants you to create an array with a size decided by the user, then have the user add its values (integers) and finally have the program sum its values.
There are plenty of ways to do it and I already know how to but my problem is that I just can't understand Hackerrank's code sample in C# it gave me. I commented the parts I don't understand, which is most of it:
static int simpleArraySum(int n, int[] ar) {
// Complete this function
int sum = 0;
foreach( var item in ar){
sum += item;
}
return sum;
}
static void Main(String[] args) {
//I know what this does
int n = Convert.ToInt32(Console.ReadLine());
//I am lost here, just why create a string array and add the split method?
string[] ar_temp = Console.ReadLine().Split(' ');
//I dont understand here neither, what is it converting? What is the parse for?
int[] ar = Array.ConvertAll(ar_temp,Int32.Parse);
//Why send the n when all you need is the array itself?
int result = simpleArraySum(n, ar);
Console.WriteLine(result);
}
I know some people hate HackerRank, and honestly, I do too but it does gives me some nice ways to test my limited skills in coding with c# and testing my logic. So, if there are better sites that helps you test your logic as a CS please share them with me.
Here is the code I made to solve this problem in Visual Studio but for some stupid reason Hackerrank wont accept it unless I make custom inputs:
//This code can be potentially shorter using the code commented further below.
//For practice's sake, it was made longer.
static int simpleArraySum(int[] arr_temp)
{
int total = 0;
foreach (var item in arr_temp)
{
total += item;
}
return total;
}
static void Main(String[] args)
{
int n = Convert.ToInt32(Console.ReadLine());
int[] arr_temp = new int[n];
for (int i = 0; i < n; i++)
{
arr_temp[i] = Convert.ToInt32(Console.ReadLine());
}
int result = simpleArraySum(arr_temp);
//int result = arr_temp.Sum();
Console.WriteLine(result);
Console.ReadLine();
}
You need to convert to string array since if you're on the main method, all it gets are string values from the argument list. To get the sum then you need to convert the string into a usable number / integer.
I agree that it doesn't make sense to send the first argument n in simpleArraySum because n is simply unused.
as for the part int[] ar = Array.ConvertAll(ar_temp,Int32.Parse); it simply tries to take in all the integers into the array. It is also risky because if you accidentally pass in a string then it will throw an error i.e. pass in "3 4 1 f" <- f will throw an exception, unless this is the desired behaviour.
Personally I think the main method should not be interested in getting involved too much with the data, the heavy lifting should be done in the methods. The better version perhaps would be to modify simpleArraySum and refactor that line in like:
static int simpleArraySum(string input)
{
String[] fields = input.Split(null);
List<int> vals = new List<int>();
foreach (string i in fields)
{
var j = 0;
if (Int32.TryParse(i, out j)) vals.Add(j);
}
int sum = 0;
foreach (var item in vals)
{
sum += item;
}
return sum;
}
I introduced the use of generic list because it's more readable if not cleaner, although the use of List might look overkill to some programmers and might not be as light weight as just using an array, hence on the other hand you can easily stick to using arrays except that it needs to be initialized with the length i.e. int[] vals = new int[fields.Length]; Roughly:
static int simpleArraySum(string input)
{
String[] fields = input.Split(null);
int[] vals = new int[fields.Length];
for (int i = 0; i < fields.Length; i++)
{
var j = 0;
if (Int32.TryParse(fields[i], out j)) vals[i] = j;
}
int sum = 0;
foreach (var item in vals)
{
sum += item;
}
return sum;
}
here my code i hope that helps
static int simpleArraySum(int[] ar,int count) {
if (count > 0 && count <= 10000)
{
if (count == ar.Length)
{
if (!ar.Any(item => (item < 0 || item >= 10000)))
{
return ar.Sum();
}
}
}
return 0;
}
and in main
int arCount = Convert.ToInt32(Console.ReadLine());
int[] arr = Array.ConvertAll(Console.ReadLine().Split(' '), arTemp => Convert.ToInt32(arTemp));
int result = simpleArraySum(arr, arCount);
Console.WriteLine(result);
since Array.ConvertAll() takes a string and convert it to one type array
int or float for example
For users still looking for a 100% C# solution: In above mentioned coding websites do not modify the main function. The aim of the test is to complete the function via the online complier.
using System.Linq;
public static int simpleArraySum(List<int> ar)
{
int sum = ar.Sum();
return sum;
}

Read a file to List<int> [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I am needing to create a list of numbers from an uploaded file, if the numbers have "-" representing a range, I need to split the numbers, making the first number a start, iterate through til it gets to the second number. I know I will be storing the numbers in a List, I'm just not sure on how to break out the numbers in the file with "-", Here is an example of the file:
099985-10043
102609-102886
102917-102921
106100-106101
110684-110685
114886-114887
117765-117766
120604-120605
121157-121158
121627-121911
122539
and here is where I am with the code:
if(string.IsNullOrEmpty(fileName.Text)) return;
_MissingInt = new List<int>();
var lines = File.ReadAllLines(fileName.Text);
foreach (string line in lines) {
...need help with logic...
}
I would greatly appreciate any direction and help as my programming skills are pretty weak and I am learning...this is not homework
I will assume that the file contains lines which can have two int values maximum, separated by -. Let's suppose we have a class like this:
class Interval {
public int left;
public int right;
public bool hasRight;
public Interval(int left, int right) {
this.left = left;
this.right = right;
hasRight = true;
}
public Interval(int left) {
this.left = left;
hasRight = false;
}
}
Now let's implement a parser method:
protected Interval parse(String line) {
String[] parts = line.Split(new string[] {"-"});
int left, right;
if (!Int32.TryParse(parts[0], left)) {
return null; //Invalid interval
}
return ((parts.length <= 1) || (!Int32.TryParse(parts[1], right))) ? (new Interval(left)) : (new Interval(left, right));
}
And another:
protected Interval[] aggregateParse(String[] lines) {
Interval[] intervals = new Interval[lines.Length];
for (int i = 0; i < lines.Length; i++) {
intervals[i] = parse(lines[i]);
}
return intervals;
}
This could be used to generate intervals. If we need to get the integers between the edges of the interval and store them, then we can use a for cycle, starting from the left edge and ending at the right edge, filling an array of right - left - 1 size, which might be a member of interval. The problem is that an interval which is opened to the right will never end, so make sure you do this wisely.
Linq-style solution that supports all wrong input like strings and empty lines. For example:
1
sfd
2
5-10
11-fdfd
12 13
14
int x;
var res = lines
// filter out empty lines
.Where(line => !string.IsNullOrEmpty(line))
// convert ranges to pairs
.Select(line => line.Split('-'))
// filter out not numbers
.Where(line => line.All(number => int.TryParse(number, out x)))
// convert all strings to int
.Select(item => item.Select(int.Parse).ToList())
.SelectMany(item =>
{
if (item.Count > 1)
{
return Enumerable.Range(item[0], item[1] - item[0] + 1);
}
return item;
})
.ToList();
I didn't agree with Badiparmagi's answer as its adding string/character to int list, its not compilable code.
Here giving you my tested attempt. I hope it may help you.
if (string.IsNullOrEmpty(fileName.Text)) return;
var _MissingInt = new List<int>();
var lines = File.ReadAllLines(fileName.Text);
foreach (var line in lines)
{
if(string.IsNullOrEmpty(line))
continue;
if (line.Contains("-"))
{
var range = line.Split('-');
int startNumber;
int endNumber;
if(int.TryParse(range[0], out startNumber) && int.TryParse(range[1]), out endNumber)
for (var i = startNumber; i < endNumber; i++)
{
_MissingInt.Add(i);
}
}
else
{
int num;
if(int.TryParse(line, out num))
_MissingInt.Add(num);
}
}

List being altered in recursive calls while passing clones of the list as argument (C#) [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm creating an algorithm to solve sudoku's using Constraint Propagations and Local Search ( similar to Norvig's ). For this I keep track of lists of possible values for each of the squares in the sudoku. For each attempt to try to assign a new value to a square I clone the array and pass it to the algorithm's search method recursively. However, somehow this the list is still being altered. The method it concerns is:
List<int>[,] search(List<int>[,] vals)
{
if (vals == null)
return null;
if (isSolved(vals))
return vals;
//get square with lowest amt of possible values
int min = Int32.MaxValue;
Point minP = new Point();
for (int y = 0; y < n * n; y++)
{
for (int x = 0; x < n * n; x++)
{
if (vals[y, x].Count < min && vals[y, x].Count > 1)
{
min = vals[y, x].Count;
minP = new Point(x, y);
}
}
}
for(int i=vals[minP.Y, minP.X].Count-1; i >= 0; i--)
{
//<Here> The list vals[minP.Y, minP.X] is altered within this for loop somehow, even though the only thing done with it is it being cloned and passed to the assign method for another (altered) search afterwards
Console.WriteLine(vals[minP.Y, minP.X].Count + "-" + min);
int v = vals[minP.Y, minP.X][i];
List<int>[,] newVals = (List<int>[,])vals.Clone();
List<int>[,] l = search(assign(minP, v, newVals));
if (l != null)
return l;
}
return null;
}
The list vals[minP.Y, minP.X] is somehow altered within the for loop which causes it to eventually try to pass squares to the assign method that have 1 (or eventually even 0) possible values. The Console.Writeline statement shows that the vals[minP.Y, minP.X].Count will eventually differ from the 'min' variable (which is defined as the same above the for loop).
If anyone could help me out on how the list is altered within this for loop and how to fix it it'd be much appreciated!
Best regards.
EDIT: The methods in which these lists are edited (in a cloned version however):
List<int>[,] assign(Point p, int v, List<int>[,] vals)
{
int y = p.Y, x = p.X;
for (int i = vals[y, x].Count - 1; i >= 0; i--)
{
int v_ = vals[y, x][i];
if (v_ != v && !eliminate(p, v_, vals))
return null;
}
return vals;
}
bool eliminate(Point p, int v, List<int>[,] vals)
{
if (!vals[p.Y, p.X].Remove(v))
return true; //al ge-elimineerd
// Update peers when only 1 possible value left
if (vals[p.Y, p.X].Count == 1)
foreach (Point peer in peers[p.Y, p.X])
if(!eliminate(peer, vals[p.Y, p.X][0], vals))
return false;
else if (vals[p.Y, p.X].Count == 0)
return false;
// Update units
List<Point> vplaces = new List<Point>();
foreach (Point unit in units[p.Y, p.X])
{
if (vals[unit.Y, unit.X].Contains(v))
{
vplaces.Add(unit);
if (vplaces.Count > 1)
continue;
}
}
if (vplaces.Count == 0)
return false;
else if (vplaces.Count == 1)
{
Console.WriteLine("test");
if (assign(vplaces[0], v, vals) == null)
return false;
}
return true;
}
Your problem is with
List<int>[,] newVals = (List<int>[,])vals.Clone();
Array.Clone() doesn't do what you think it does here. List<int>[,] represents a two-dimensional Array of List<int> objects - effectively a three-dimensional array. Since List<int> isn't a basic value type, .Clone() creates a shallow copy of the array.
In other words, it creates a brand new two-dimensional Array which has, for each value, a pointer to the same List<int> that the old one does. If C# let you manipulate pointers directly, you could start changing those, but since it doesn't, any time you access the underlying List<int>, you're getting the same one regardless of whether it's before the Clone() or after.
See the documentation on it here, and some solutions are here and here.
Effectively, you need to rewrite that line so that rather than copying the array itself, it copies all the values into new List<int>'s.

How to sort a List<Process> by Window Title [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am sure I would do this, but the way I am thinking how to achieve this makes me sad, so I am asking for better way
List<Process> myList = new List<Process>();
Process[] processlist = Process.GetProcesses(); // Load all existing processes
// Pin existing sessions to the application
foreach (Process p in processlist)
{
if (p.MainWindowTitle.Contains("TX")) // schema is like TX1 => TX10, but this loop is not sorted at all
{
myList.Add(p); // Unsorted list when looking by MainWindowTitle property
}
}
Sorry fot nor precising the question about what kind of sorting I want to achieve
[0] TX1
[1] TX2
...
[5] TX6
etc.
You could try something like this:
var myList = processlist.Where(p=>p.MainWindowTitle.Contains("TX"))
.OrderBy(p=>p.MainWindowTitle)
.ToList();
How about using LINQ's OrderBy and a simple custom comparer. In this case this might be enough. From the information you gave us it should work for you.
class Program
{
static void Main(string[] args)
{
var names = new string[] { "TX2", "TX12", "TX10", "TX3", "TX0" };
var result = names.OrderBy(x => x, new WindowNameComparer()).ToList();
// = TX0, TX2, TX3, TX10, TX13
}
}
public class WindowNameComparer : IComparer<string>
{
public int Compare(string x, string y)
{
string pattern = #"TX(\d+)";
var xNo = int.Parse(Regex.Match(x, pattern).Groups[1].Value);
var yNo = int.Parse(Regex.Match(y, pattern).Groups[1].Value);
return xNo - yNo;
}
}
The WindowNameComparer reads (parses) the numbers attached to the TX and calculates the difference which is then used for sorting according to this table for the IComparer.Compare Method
Value Meaning
Less than zero x is less than y.
Zero x equals y.
Greater than zero x is greater than y.
Well, I made this almost without linq, but I guess it's overkill
Process temp = null;
for (int i = 0; i < Games.Count; i++)
{
for (int sort = 0; sort < Games.Count - 1; sort++)
{
string title1 = Games[sort].MainWindowTitle;
string title2 = Games[sort+1].MainWindowTitle;
int titleAsIntSum1 = title1.Sum(b => b); // This will work in this case
int titleAsIntSum2 = title2.Sum(b => b);
if (titleAsIntSum1 > titleAsIntSum2)
{
temp = Games[sort + 1];
Games[sort + 1] = Games[sort];
Games[sort] = temp;
}
}
}

Categories

Resources