Put last 10 elements of list<> into other list<> [duplicate] - c#

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I have a list<>, filled with objects of my class. That one is working fine.
Now I want to load the last 10 elements to a new list<>, which is sorted upside-down. So the last Element will be the first of the new List<> and the 10th will be the last one in the new List<>.
Usually this shouldn't be such a hard task but I don't know... it iterates on the right way and should work in my opinion.
Both Lists<> are Lists<lastChanges>. lastChange is my class.
Here's what I got now:
// x represents the amount of elements for the new List<>
int x = 10;
// elems is the old list. if it contains less than 10 elements,
// x should be the amount instead of 10
if (elems.Count < 10)
{
x = elems.Count;
}
// The start-index is made by elems.Count -> 10 Items -> the 10th item
// would get the index '9'
// as long as i is greater than the amount of the large List<>
// minus the wanted amount for the new List<>
// the loop is going to repeat
for (int i = elems.Count-1; i > elems.Count - x; i--)
{
// lastChanges is my class which both Lists are filled with
lastChanges lastArt = elems[i];
if (lastArt != null)
{
items.Add(lastArt);
}
}
What am I missing? I really do not think I'm still a beginner (of course much to improve) but I can't find an error here...
For example:
The elems-List does contain 2 Elements,
then x would be equal 2.
The for-loop would start:
for(int i=1;i>0;i--)
so the loop would run twice.
In the first run there would be 'lastArt' set equal to the second object of 'elems' and than be added to 'items,
in the second run, the first item would be added to 'items'.
So, both items are added to 'items', everything is fine.
But why do I keep getting errors?
Both Objects are definetely != null...
Thank you!
edit:
I always get a 'NullReferenceException' in this line:
items.Add(lastArt);
Both Objects are definetely != null, so in my opinion it has to be an error in my iteration.

try to use LINQ
var result = data.Skip(data.Count - 10).Take(10);
List<SomeType> list = new List<SomeType>(result.Reverse());

It's easier to make your loop count up.
Rather than trying to keep track of i counting back from the last element, start with 1 and count up.
int numElements = 10; // or however you want from the end
for (int i = 1; i <= numElements && i <= elems.Count; i++)
lastItems.Add(elems[elems.Count - i]);
It's even easier to use LINQ.
List<MyClass> lastElements = elems.Reverse().Take(10).ToList();

Related

Filter a list of integers based on integer multiples - C#

I am trying to filter a list of int based on multiples of a specific number, but I am not sure how to do this. I have searched this forum and found nothing related, but apologies in advance if I'm wrong.
Here is my code:
int val = 28;
List<int> divisible = new List<int>();
for (int i = 1; i <= val; i++) {
divisible.Add(i);
}
foreach(var d in divisible)
{
if(val % d == 0)
{
// do something
}
else
{
// get rid of all multiples of the number that "val" is not divisible by
}
}
Basically, this code should create a divisible list from 1 to 28. If val is divisible by one of the numbers in the list, thats fine, but if it falls into else, I want to be able to filter out all multiples of that number out of the current list we are looping through.
The next number that wouldn't be divisible would be 3 in this example, so in the else get rid of 6, 9, 12, ... etc.
Your code is fine, but you're just missing the actual code to remove the item. But there is a caveat: You cannot modify a list when you are looping through it using foreach. There are a couple ways to handle that:
Depending on your requirements, maybe just don't add them in the first place. Move your val % d == 0 condition into the for loop that adds the values, and just don't add the values that are divisible by d.
Make a new list (List<int> toRemove) where you keep track of all the values you need to remove. After you're done the foreach loop, loop through your toRemove list and use divisible.Remove(value) to remove those.
Change your foreach to a for loop, which will allow you to use divisible.RemoveAt(i). But you will have to make sure you don't skip a value on the next iteration of the for loop (since removing a value changes the size of the list).
I agree with Gabriel. You cannot alter a underlying enumeration while traversing it with with foreach. The easiest thing to do would be to convert it to a for loop.
Also in the initial population of your list try using the newer way
var divisible = Enumerable.Range(1, val).ToList();
then do
for(int 0 = 1; i < val; i++)
{
if(val % d == 0)
{
// do something
}
else
{
divisible.RemoveAt(i);
}
}

Pre-decrement of value in a for loop is not correctly decreasing value on first loop

I have the following for loop in my code (using C#)
for (int i = 150; i >= 75; --i)
{
print("I holds " + i);
images[i].gameObject.SetActive(false);
}
trying to run through each item in a list, and disable the object. The list holds 150 objects (but since it starts at value zero, the final reference position is 149)
So, I figured a for loop was a good way to iterate through them all. Yet, I try to decrease the value of i to 149 for the first run of the loop, but it still passes a value of 150 into the loop in the first run, which throws the expected ("Argument is out of range") error.
Can anyone work out why the decreased value isn't correctly being passed to the loop?
I tried both decreasing it before and after the first run of the loop, but both times it passes a value of 150 into the loop.
I feel this should be a relatively simple issue to solve, yet it's not working as I expected it to do!
for (int i = 10; i >= 0; --i)
is the same as
for (int i = 10; i >= 0; i--)
i does not decrease/increase on the first loop. This is for many languages. Just start with 149 and it works.
Answer for "Can anyone work out why the decreased value isn't correctly being passed to the loop?"
Another way to loop through all items of an array without caring of actual indices is to make use of a foreach statement:
foreach(var image in images)
{
image.gameObject.SetActive(false);
}
If you want to use a for statement. I would suggest you write it as below:
for(var i=0; i<images.Length; i++)
{
image[i].gameObject.SetActive(false);
}
Doing so, you are pretty confident that you are not going to be out of the array's size. You start at the element at the position with index of 0 and you read the last item stored in the array, in the position of images.Length-1.
Update
If you want to update only the first 75 items (where 75 is half the total items in the array) in your array you could try this:
for(var i=0; i<images.Length/2; i++)
{
image[i].gameObject.SetActive(false);
}

Looking to sort array from smallest to largest remove duplicates [duplicate]

This question already has answers here:
How do I remove duplicates from a C# array?
(28 answers)
Closed 5 years ago.
As the title says, I'm taking a free online course in C# and I've been stuck on this question for a bit. It's asking to write function with an array that sorts from smallest to largest and removes duplicate entries. The course has gone over arrays and sorting, but not how to remove duplicates so far. If you could help with this I'd appreciate it greatly.
There are a couple of ways to accomplish the task at hand, However, the quickest way is probably using Linq:
int[] array = { 3, 5, 1, -9, 4, 8, 23, -657, 54 };
array = array.Distinct().OrderBy(x => x).ToArray();
While there may be some more efficient methods, to help you understand the concepts a bit more, here's a simple technique.
You'll need to keep track of what entries you've already seen. Create a new list, and add the first number in the array to it. Then, take the second number in the array, and compare it to every number in your list. If it ever shows up in this list, it's a duplicate, so you can skip this number and move to the next element in the array.
ArrayList list = new ArrayList();
for (int i = 0; i < yourUnsortedArray.length; ++i) {
bool hasDuplicate = false;
for (int entry in list ) {
if (yourUnsortedArray[i] == entry) {
hasDuplicate = true;
break;
}
}
if (hasDuplicate == false) {
list.Add(yourUnsortedArray[i]);
}
}
//list will have no duplicates here.
Bonus optimization: It will help if you sort the array first. This way, you only ever have to look at the most recently added number in your list, instead of walking down the entire list every single time.
ArrayList list = new ArrayList();
for (int i = 0; i < yourSortedArray.length; ++i) {
if (list.length == 0 || list[list.length - 1] != yourSortedArray[i]) {
list.Add(yourSortedArray[i]);
}
}

Looping and changing a list - remove doesn't always work

I'm trying to go through a loop 40 times and changing a list in the process.
This is the code:
for (int i = 0; i < 40; i++)
{
location = rand.Next(rows.Count);
rank = rand2.Next(pondRanks.Count);
ComputerPonds[rows[location]].Rank = (PondRank)pondRanks[rank];
rows.Remove(location);
pondRanks.Remove(rank);
}
For some reason the remove doesn't happen all the time, and only sometimes. Anyone has a suggestion?
Both of the list are List , they have 40 elements, and I want to remove the element itself.
Even when debugging I can see that the list count isn't the same (they both have the same initial numbers and they both need to do remove at this loop). If it matters, I'm working on windows phone platform..
I'm pretty sure you should be using List.RemoveAt not List.Remove. RemoveAt will remove the item at the specified index, whereas Remove will look for that object you passed in and remove it from the List if it's in there. But I'm pretty sure that looking at your code that location and rank represent the index, not the objects themselves.
for (int i = 0; i < 39; i++)
{
location = rand.Next(rows.Count);
rank = rand2.Next(pondRanks.Count);
ComputerPonds[location].Rank = (PondRank)pondRanks[rank];
rows.RemoveAt(location);
pondRanks.RemoveAt(rank);
}
EDIT: You may also want to consider making sure that your rows and pondRanks have enough elements (39) before starting the loop (or altering the i < 39 to max out at the upper limit of their length)

Clearing a list using a for loop

I'm making a Black Jack game, and at the start of every new round I need to clear the list of cards that represents the Player's and the Dealer's hands. I used this to do so:
public void ClearPlayerHand()
{
for (int i = 0; i < PlayerHand.Count; ++i)
{
PlayerHand.Remove(PlayerHand[i]);
}
}
Problem is I always seem to be left with one card left in the list, or I receive an out of bounds error, no matter how I change the value of i, what is the best method of removing all the elements from the PlayerHand?
If your collection PlayerHand implements ICollection<T> you can just call the .Clear() method.
A common implementation of this interface is List<T>.
If you do want to clear a List<T> via a for loop, you should use a reverse for loop. The reason for this is that as you remove an item from the list, it will shift all the index's down one, and you could easy run into index out of bounds exceptions.
An example of this would be:
for (int i = PlayerHand.Count - 1; i >= 0; i--)
{
PlayerHand.RemoveAt(i);
}
The other answers are right: use Clear.
But, if you wanted to do this with a loop and Remove calls, here's how you would do it:
for(int i = PlayerHand.Count - 1; i >= 0; i--)
{
PlayerHand.RemoveAt(i);
}
Reversing the direction of the iteration is the real trick.
This is the best/easiest way to do it.
PlayerHand.Clear();
Reason for out of bounds
As for why you are receiving the out of bounds exception, it's happening because you're removing elements from the list but continually counting up. You would want the last operation to remove i = 0 but it keeps counting.
Say PlayerHand has 3 items in it, the following occurs:
i = 0
remove PlayerHand[0] (it now contains 2 elements)
i = 1
remove PlayerHand[1] (it now contains 1 element)
i = 2
remove PlayerHand[2] (this throws an exception as only PlayerHand[0] exists)
Normally you would count backwards in this case:
for (int i = PlayerHand.Count - 1; i >= 0; i--)
Alternatively, you can consider using data binding and then you should update the ItemSource, instead of directly manipulating the listbox or listview items.
List<T> SomeSource=...
PlayHand.ItemSource=SomeSource;
SomeSource.Clear();
Another suggested approach beside Clear method, you can also use RemoveAll to either remove all or part of list
// Remove all items
PlayerHand.RemoveAll(x => true);
// Remove part of list
PlayerHand.RemoveAll(x => ConditionMethod(x));

Categories