Foreach loop not acting like I thought it would [closed] - c#

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 2 years ago.
Improve this question
I have been working on on this problem for awhile I have two arrays in parallel that are the same length. I have nested foreach loops to compare the arrays so I can tell what number is greater. One number is randomly generated and the other is gathered from user input. The problem I'm having is the number that is randomly generated is being compared to each user input before moving to the next randomly generated number. This is my code:
Random r = new Random();
int length = 10;
int[] ranNum = new int[length];
int[] userNum = new int[length];
for (int i = 0; i < length; i++)
{
ranNum[i] = r.Next(1, 100);
}
for (int i = 0; i < length; i++)
{
Console.WriteLine("Enter a number between 1 and 100");
userNum[i] = Convert.ToInt32(Console.ReadLine());
}
foreach(int rn in ranNum)
{
foreach(int ui in userNum)
{
if (rn < ui)
{
Console.WriteLine(rn + " is less than " + ui);
}
else if (rn > ui)
{
Console.WriteLine(rn + " is greater than " + ui);
}
else
{
Console.WriteLine(rn + " is equal to " + ui);
}
}
}
I'm sure I'm missing something obvious any help would be appreciated Thank you in advance

Nested foreach loops are exactly like nested for loops in that they loop through each of the outer values with all of the inner values. If you're just trying to compare the values one-to-one, you'll need to iterate through both arrays at the same time. You can do this by grabbing their iterators and using a while loop; You can use LINQ and Zip both arrays; Or, you can use another for loop, like you used to generate your arrays, and use a common index to iterate through both loops:
for (int i = 0; i < length; i++) {
var rn = ranNum[i];
var ui = userNum[i];
if (rn < ui) {
Console.WriteLine(rn + " is less than " + ui);
} else if (rn > ui) {
Console.WriteLine(rn + " is greater than " + ui);
} else {
Console.WriteLine(rn + " is equal to " + ui);
}
}
Depending on what you're doing with these values, you might consider consolidating these loops, but this is how you would iterate through both at the same time.

There are TWO nested foreach loops here, which will create every possible combination of values. If you want to just match by index you can use a single for loop, or you can use the IEnumerable.Zip() function:
var results = ranNum.Zip(userNum, (rn, ui) => {
if (rn < ui) return $"{rn} is less than {ui}";
if (rn > ui) return $"{rn} is greater than {ui}";
return $"{rn} is equal to {ui}";
});
foreach (var result in results)
{
Console.WriteLine(result);
}

Related

Problem sorting objects based on value of its properties

I'm sitting here with a school project I can't seem to figure out; I am to create a console application that let's the user enter a number of salesmen for a hypothetical company. The information about the salesmen includes their name, district and number of sold items. The salesmen are then to be sorted into different levels according to the number of sold items. Finally, the salesmen are to be printed to the console. The printing should be done one level at the time, if for instance two salesmen reached level one and one reached level 2, the console should look something like:
John Johnsson, someDistrict, 33 items sold
Mary Mara, someOtherDistrict, 40 items sold
2 salesmen reached level 1
Judy Juggernut, anotherDistrict, 67 items sold
1 salesmen reached level 2
And it's the printing part in question that gives me trouble. When the user enters information a new object of a salesman-class is created and stored in an array of salesmen. The number of items sold for each salesman is then checked and each salesman is assigned a level. The array is then sorted using bubblesort, to have the salesman with the least amount of sales on salesmanArray[0] and so on.
Everything works fine until its time to print the results to the console. I tried to write a method for it:
public static void sortering(Salesman[] salesmenArray)
{
Salesman[] level1 = new Salesman[salesmenArray.Length];
Salesman[] level2 = new Salesman[salesmenArray.Length];
Salesman[] level3 = new Salesman[salesmenArray.Length];
Salesman[] level4 = new Salesman[salesmenArray.Length];
for (int i = 0; i < salesmenArray.Length - 1; i++)
{
if (salesmenArray[i].level == 1)
{
level1[i] = salesmenArray[i];
} else if (salesmenArray[i].level == 2)
{
level2[i] = salesmenArray[i];
} else if (salesmenArray[i].level == 3)
{
level3[i] = salesmenArray[i];
} else if (salesmenArray[i].level == 4)
{
level4[i] = salesmenArray[i];
}
}
if (level1.Length != 0)
{
for (int i = 0; i < level1.Length - 1; i++)
{
Console.WriteLine("Name: " + level1[i].name);
Console.WriteLine("District: " + level1[i].district);
Console.WriteLine("Items sold: " + level1[i].itemsSold);
}
Console.WriteLine("" + (level1.Length - 1) + " sellers have reached level 1");
}
//Same thing for level 2, 3 and 4
}
What I'm trying to do is 4 new arrays for the different levels. I then loop through the array with all the salesmen and place the salesmen into the arrays in accordance to the number of sold items. I then check if the level-arrays are empty. If they aren't, I loop through them printing out the name, district and items sold for each salesman. Finally also printing out how many sellers there are in each level. When running the program, I get an error on the line
Console.WriteLine("Name: " + level1[i].name);
Saying "System.NullReferenceException has been thrown "Object reference not set to an instance if an object".
I would assume that means level1[i].name isn't referencing to an object but I don't really know how to go from there... Any advice or pointers would be greatly appriciated!
You are getting a System.NullReferenceException because you are initializing the level arrays with the same length as the salesmen array, but you are only adding salesmen to the level arrays based on their level.
So there will be not initialized null elements in the level arrays, and when you try to access the name property of a null element, you get the exception because you try to read property of absent element.
To fix this, you may use List<Salesman> instead of Salesman[]. List<T> is a generic dynamic array and you can iterate over its items in the same way:
public static void sortering(Salesman[] salesmenArray)
{
var level1 = new List<Salesman>();
var level2 = new List<Salesman>();
var level3 = new List<Salesman>();
var level4 = new List<Salesman>();
for (int i = 0; i < salesmenArray.Length; i++)
{
if (salesmenArray[i].level == 1)
{
level1.Add(salesmenArray[i]);
}
else if (salesmenArray[i].level == 2)
{
level2.Add(salesmenArray[i]);
}
else if (salesmenArray[i].level == 3)
{
level3.Add(salesmenArray[i]);
}
else if (salesmenArray[i].level == 4)
{
level4.Add(salesmenArray[i]);
}
}
if (level1Count > 0)
{
for (int i = 0; i < level1.Count; i++)
{
Console.WriteLine("Name: " + level1[i].name);
Console.WriteLine("District: " + level1[i].district);
Console.WriteLine("Items sold: " + level1[i].itemsSold);
}
Console.WriteLine("" + level1Count + " sellers have reached level 1");
}
//Same thing for level 2, 3 and 4
}
Here is some other improvments then you can do with your code. For example if Salesman.level may contains only values form the list [1, 2, 3, 4] you can store levels in the List of List<Salesman> or in the array of List<Salesman> and add items in the easier way. Also string interpolation is an easier, faster, and more readable string concatenation syntax.
// here we creates a new array of lists and initialize it with 4 empty lists of Salesman
var levels = new List<Salesman>[]
{
new List<Salesman>(),
new List<Salesman>(),
new List<Salesman>(),
new List<Salesman>()
};
foreach(var salesmen in salesmenArray)
{
// (salesmen.level - 1)-th list stores salesmen with that level
levels[salesmen.level - 1].Add(salesmen);
}
// you can iterate salesmen of all levels with nested loops
for(int level = 0; level < levels.Lenth; level++)
{
foreach(var salesman in levels[level])
{
Console.WriteLine($"Name: {salesman.name}");
Console.WriteLine($"District: {salesman.district}");
Console.WriteLine($"Items sold: {salesman.itemsSold}");
}
// Count property gets the number of elements contained in the List<T> so you don't need to decrement this value for display the number of salesmen with this level
Console.WriteLine($"{levels[level].Count} sellers have reached level {level + 1}");
}
Finally there is an interesting mechanism to manipulate collections in .NET called LINQ. You can use LINQ syntax to select, filter, group and aggregate data. LINQ is readable efficiency and powerful tool. Here's a sample of your code rewritten with LINQ:
foreach(var group in salesmenArray
.GroupBy(salesman => salesman.level)
.OrderBy(groups => groups.Key))
{
foreach(var salesman in group)
{
Console.WriteLine($"Name: {salesman.name}");
Console.WriteLine($"District: {salesman.district}");
Console.WriteLine($"Items sold: {salesman.itemsSold}");
}
Console.WriteLine($"{group.Count()} sellers have reached level {group.Key}");
}
Where is the bubble sort? Sort the array first, then loop through the array with counters to count each level and print the output from the same loop.
// bubble sort
for (int i = 0; i < salesmenArray.Length; i++)
for (int j = 0; j < salesmenArray.Length - 1; j++)
if(salesmenArray[j].itemsSold > salesmenArray[j+1].itemsSold)
{
//swap positions
//...
}
int counter = 0;
int lastLevel = 1; //if 1 is the min level
for (int i = 0; i < salesmenArray.Length; i++)
{
if(salesmenArray[j].level != lastLevel)
{
//print summary
//...
counter = 0; //reset counter
}
// print detail lines
Console.WriteLine("Name: " + level1[i].name);
Console.WriteLine("District: " + level1[i].district);
Console.WriteLine("Items sold: " + level1[i].itemsSold);
counter++;
}
//print final summary for last level
//...
The ... are lines for you to fill.
Vadim's answer details why your code is failing. He proposed a way to solve the problem via Lists. I would also follow that road.
On the other hand, your approach was valid, but not very efficient and has a few traps for yourself (as Vadim mentioned, you are creating 4 level arrays with the same size of the total of salesmen, then you assign them to each level via i, leaving some null gaps). If you want your approach to work, in the printing for-loop, before getting level1[i].name, check that level1[i] is not null.
If you are using an IDE, I would recommend you to put a breakpoint inside the for-loop and see the contents of level1.
Good luck learning!

How to register multiple values in a variable?

I've been trying to display all the pair numbers in a loop that goes from 1 to 100 and increments 1 each time. I try to display the pair numbers like they would in this "if" code block.
for (var i = 0; i < 100; i++)
{
if (i % 2 == 0)
{
Console.WriteLine(i);
}
But I want to save these in a string called "losPares", which I attempt to do display in this way:
static void Main(string[] args)
{
var counter = 0;
var losPares = 0;
for (var i = 0; i < 100; i++)
{
if (i % 2 == 0)
{
counter++;
losPares = i;
}
}
Console.WriteLine("hay " + counter + " numeros pares.");
Console.WriteLine("estos son " + losPares);
}
Which is kinda weird. In the first code example the console will print out all the pair numbers. In the second one it will only print the last of them, 98. I don't really know what to do, tried creating an array instead of a variable but when I try to store "i" in it i get the following error:
Cannot implicitly convert type 'int' to 'int[]'
aAd if i try to cast "i" as a string when losPares is an array instead of a variable, like this:
int[] losPares = new int[100];
for (var i = 0; i < 100; i++)
{
if (i % 2 == 0)
{
counter++;
losPares = Convert.ToBase64CharArray(i);
}
I get the following error.
CS1501 No overload for method 'ToBase64CharArray' takes 1 arguments
I don't really know what to do. Thanks a bunch for reading!
Your console is printing last element because you are assigning value of i to losPares in your sencond code snippet. This assignment operator assinging value of i to losPares in each iteration where i % 2 condition is satisfied.
Instead of assigning value to integer, use List to store i and at the end of for loop print all elements from list.
public static void Main(string[] args)
{
var losPares = List<int>();
var counter = 0;
for (var i = 0; i < 100; i++)
{
if (i % 2 == 0)
{
counter++;
//Below line was executing everytime and in each execution this line was assigning value of i to losPares
//losPares = i;
losPares.Add(i);
}
}
Console.WriteLine("hay " + counter + " numeros pares.");
Console.WriteLine("estos son " + string.Join(Environment.NewLine, losPares));
}
An integer will only have 1 value and cannot have multiple values at the same time. If you want to keep track of all the values from the loop, you will have to save all the values in a collection / list or an array. Following example shows how to save them in a List.
var counter = 0;
var losPares = new List<int>();
for (var i = 0; i < 100; i++)
{
if (i % 2 == 0)
{
counter++;
losPares.Add(i);
}
}
Console.WriteLine("hay " + counter + " numeros pares.");
Console.WriteLine("estos son " + string.Join(" ", losPares));
You can create a list of ints (losPares) and then display that at the end. What you are doing is assigning a value to losPares and then overriding it again and again until the last iteration in you loop. That is why your losPares always have the last value.
As per my understanding below are my takes. First one is printing all values because the printing part is inside the loop but in second both print statements are outside the for loop block because of which it stores the last value of loop and display it.
You can create a string variable and append all the numbers to that string.
string temp = ''; and then in for loop you can do something like temp+=i + ' '; It is better to use string builder because of immutable property of string.
If you want to use array. Below is the way to assign values in a array.
int[] losPares = new int[100];
In a for loop you can use losPares[i] = i; This will fill your array.

Efficiently generate all combinations (at all depths) whose sum is within a specified range [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 3 years ago.
Improve this question
I have a set of 80 numbers and I would like to find the list of combinations which totals up to a given number. The below code works fine but its takes too long could someone please help me with an enhanced version which would process it faster ?
public void sum_up(List<int> numbers, int target)
{
sum_up_recursive(numbers, target, new List<int>());
}
public void sum_up_recursive(List<int> numbers, int target, List<int> partial)
{
int s = 0;
foreach (int x in partial) s += x;
if (s == target)
val +=" sum(" + string.Join(",", partial.ToArray()) + ")=" + target + Environment.NewLine;
if (s == target && string.Join(",", partial.ToArray()).Contains("130") &&
string.Join(",", partial.ToArray()).Contains("104"))
{
string gg = " sum(" + string.Join(",", partial.ToArray()) + ")=" + target;
val += " || || sum(" + string.Join(",", partial.ToArray()) + ")=" + target + Environment.NewLine;
}
if (s >= target)
return;
for (int i = 0; i < numbers.Count; i++)
{
List<int> remaining = new List<int>();
int n = numbers[i];
for (int j = i + 1; j < numbers.Count; j++) remaining.Add(numbers[j]);
List<int> partial_rec = new List<int>(partial);
partial_rec.Add(n);
sum_up_recursive(remaining, target, partial_rec);
}
lblResult.Text = val;
}
private void btnCheck_Click(object sender, EventArgs e)
{
string[] vendorVal = txtvendor.Text.Split(',');
int[] myInts = Array.ConvertAll(vendorVal, s => int.Parse(s));
List<int> numbers = myInts.ToList();
int target = Convert.ToInt32(txtDifference.Text);
sum_up(numbers, target);
}
Any help is appreciated...
You recalculate the same partial sums again and again - this process takes a lot of time. If targer sum value is reasonable and you have enough memory - use dynamic programming approach.
Create array A of length (TargetSum + 1) containing lists possible variants for intermediate sums.
For every item value V make loop from sum S=TargetSum downto V (reverse traversal helps to avoid repeated using of the same item). If entry A[S - V] is not empty - add all variants from A[S - V] with addition of V into A[V]. Finally A[TargerSum] will contain all possible combinations.
Also consider memoization technique - it might be constructed from your recursive function - just remember sum variants in dictionary and reuse stored variants.

Parallel-For loops and consistency

I'm working an Euler problem with an outer and inner loop. The outer loop contains the value being checked, the inner loop controls how many test iterations pass, in this case looking for Lychrel numbers.
The outer loop works in parallel just fine, but the inner loop is extremely inconsistent. You can see from my commented out lines that I've tried a List<T> and used locking, as well as using ConcurrentQueue<T>. My initial implementation used a bool set to true (that the number IS a Lychrel number) which would get set to false if proven otherwise after n-iterations. It would then just count the number of collected Lychrel numbers. The bool operation wasn't working so well, jumping out of the inner loop (even with a lock). I even tried to implement a threadsafe boolean, but so far nothing has kept the inner loop consistent. At this point it's become a learning exercise. I'm generally familiar with threading, and use it fairly regularly even with collections, but this one stumps me as to the root cause of the problem.
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
BigInteger answer = 0;
List<long> lychrels = new List<long>();
ConcurrentQueue<long> CQlychrels = new ConcurrentQueue<long>();
long maxValue = 10000;
long maxIterations = 50;
sw.Start();
//for (int i = 1; i < maxValue; i++)
Parallel.For(1, maxValue, i =>
{
BigInteger workingValue = i;
//bool lychrel = true;
//for (int w = 1; w < maxIterations; w++)
Parallel.For(1, maxIterations, (w, loopstate) =>
{
workingValue = workingValue.LychrelAdd();
if (workingValue.ToString().Length > 1)
if (IsPalindrome(workingValue))
{
//lychrel = false;
CQlychrels.Enqueue(i);
//lock (lychrels)
//lychrels.Add(i);
loopstate.Break();
//break;
}
});
//if (!lychrel)
//lock (lychrels)
//lychrels.Add(i);
});
answer = maxValue - CQlychrels.Count();
sw.Stop();
Console.WriteLine("Answer: " + answer);
Console.WriteLine("Found in " + sw.ElapsedTicks + " ticks.");
Console.WriteLine("Found in " + sw.ElapsedMilliseconds + "ms.");
while (Console.ReadKey() == null)
{ }
Environment.Exit(0);
}
BigInteger.LychrelAdd() just takes the value and a mirror of it's value and adds them together.
I suspect, perhaps, that either that or IsPalindrome() not being threadsafe may be the cause? Setting workingValue outside of that loop and working on it inside? Something to do with BigInteger being a reference value and that reference changing?

Card Game without using arrays

We have a task to create a random hand of cards (5 cards). Where the cards can not be the same. We have yet not learnd how to use arrays so it would be nice if anyone could help us to get started without using arrays.
This is how we have started, but we can not figure out how to not get the same card twice.
static void Cards()
{
var rnd = new Random();
var suit, rank, count = 0;
while (count < 5)
{
rank = rnd.Next(13) + 1;
suit = rnd.Next(4) + 1;
if (suit == 1)
{
Console.WriteLine("Spader " + rank);
}
else if (suit == 2)
{
Console.WriteLine("Hjärter " + rank);
}
else if (suit == 3)
{
Console.WriteLine("Ruter " + rank);
}
else
{
Console.WriteLine("Klöver " + rank);
}
count++;
}
}
Thanks!
This is the sort of problem that arrays can deal with, so it would be easier to learn how to use them. Without them you need to store your 5 cards in variables (string card1, string card2, etc) then on each iteration check to see if the card matches any of these and discard it if it does, else save it. But then you have a whole bunch of conditional code to see which variable to store it in...
Much easier to just have an array
string[] cards = new string[5];
then you can just loop over the array looking for a match (something like this)
for(int idx=0; idx<5; idx++){
if(cards[idx]==thecardyouhavejustcreatedwithrandomcode){
break; //bail out of the for on a match
}
cards[iAntalKort]=thecardyouhavejustcreatedwithrandomcode;
}

Categories

Resources