collection help please - c#

I have a collection< of int's >.
1
2
3
When i remove, for example, the 2. The collection becomes 1,3.
However, when I go to add another item the list becomes
1
3
3
Because the sequence is based off the count of items in collection
is there an easy way to resequence. The example above where i'm showing 1,3 should be resequence to 1,2 and then the next new item will be a 3.

It sounds like your list can be replaced with a integer variable, since all you are "storing" here is the (1-based) index of the item in the list. Creating a "list" from 1 to n would just be int count = n. Testing if an item is in the list becomes if (item <= count). Adding an item would be count++, and removing count--.

You could rewrite your list every time you remove an object using Enumerable.Range, so the code to you would be something like this:
//execute this after remove element
void Resequence()
{
myList = Enumerable.Range(1, myList.Count).ToList();
}
so the add will be something like this
void AddElement(){
myList.Add(myList.Count + 1);
}
Note: in the add element you should remove the +1 if the list is zeroBased.

Related

Dequeue items of a list and insert new one at position 0

I have a list like this:
public List<ProjectHistoryModel> ProjectHistoryModel = new List<ProjectHistoryModel>();
Now I have Enqueue and Dequeue method like:
private void Enqueue(ProjectHistoryModel model)
{
ProjectHistoryModel.Add(model);
}
private void Dequeue(List<ProjectHistoryModel> model)
{
model.RemoveAt(4);
}
It add and remove items correctly except for one reason, when I add new item I want always add it to index [0], for example if I have a list with indexes 0,1,2,3,4,5 and new item comes I have a validation if (ProjectHistoryModel.Count == 5) so dequeue runs and remove index 5 now Enqueue method runs and add new item, but it added as index 5, I want to add it as index 0 and go throught all the others. How can I achieve that?
To add the item to the zero index use .Insert instead of .Add:
ProjectHistoryModel.Insert(0,model);
As you've experienced, .Add adds the item at the end of the list whereas for .Insert you specify the index to insert the item at. In your case, 0.
Based on #DavidG's comment, unless it is for practice then it is probably better for your needs to use Queue<T> instead of a list.

Add element to list before specific element

I have a list of items, lets say 100 items. I need to add another element before the existing element that matches my condition. What is the fastest way and the most performance optimized to do this?
ie.:
foreach (var i in myList)
{
if (myList[i].value == "myValue")
{
myList[i-1] add ("someOtherValue")
}
}
Maybe i should use other container?
First you could find the index of your item using FindIndex method:
var index = myList.FindIndex(x => x.value == "myvalue");
Then Insert at the right point:
myList.Insert(index,newItem);
Note that inserting at a given index pushes everything else forward (think about finding your item at index 0).
Consider using a LinkedList<T>. It has the advantage that inserting or removing items does not require shifting any items. The disadvantage is that items cannot be accessed randomly. You have to traverse the list starting at the first or last item in order to access the items.
myList.Insert(myList.IndexOf("myValue") - 1, "someOtherValue");
You should probably check to make sure myvalue exists first, and it is not in index 0.
int index = myList.IndexOf("myValue");
if (index >= 0)
myList.Insert(index, "myNewValue");
By the way, you should not modify your own collection or list while iterating with for-each (as in your code above).
I presume the list is an array - in which case have you tried doing this with Linq?
string[] mylist = new string[100];
// init the list
List<string> list = keys.ToList();
list.Insert(1,"somethingelse");
mylist = list.ToArray(); // convert back to array if required
if it is a List to begin with, you can skip the conversions and use Insert directly.

LINQ Intersect but add the result to a New List

I have a list called DiscountableObject. Each item on the list in turn has a Discounts collection. What I need is a list of Discounts which are common across all DiscoubtableObjects.
Code:
List<Discount> IntersectionOfDiscounts = new List<Discount>();
foreach(var discountableItem in DiscoutableObject)
{
IntersectionOfDiscounts = IntersectionOfDiscounts.Intersect(discountableItem.Discounts);
}
This will undoubtedly return an empty list because by IntersectionOfDiscounts was empty in the first instance.
What I want is to take item 1 of the DiscountableObject, compare it with the next item of DiscountableObject and so on.
I know what I am trying to do is wrong because, I am doing the intersection and the addition to the list at the same time...but how else baffles me?
How do I get around this?
Initialize IntersectionOfDiscounts to the first Discount List (if there is more than one) rather than to an empty list. You can also then skip the first item in the 'foreach' loop.
// add check to ensure at least 1 item.
List<Discount> IntersectionOfDiscounts = DiscoutableObject.First().Discounts;
foreach(var discountableItem in DiscoutableObject.Skip(1))
{
IntersectionOfDiscounts = IntersectionOfDiscounts.Intersect(discountableItem.Discounts);
}
Possibly more elegant way:
var intersection = discountableObject
.Select(discountableItem => discountableItem.Discounts)
.Aggregate( (current, next) => current.Intersect(next).ToList());
Missed your 6 minute deadline, but I like it anyway...

Deleting items in a list at once by index in c#

I am looking for a way to remove a set of indexes from a list AT ONCE. By this i mean, I have a list of indices for ex, 0,1,5,7 that i want to remove from a string list of animals. I need a way to remove all the animals at the indices 0,1,5,7 in one shot. THis is because if i iterate through the animals list and delete the animal at 0,1,5,7 at each iteration, the list structure changes and the indeces no longer apply to the updated animal list.
Thanks
Well, one option is to delete them starting with the highest one instead. For example:
foreach (var index in indexesToDelete.OrderByDescending(x => x))
{
list.RemoveAt(index);
}
For example, removing item 5 doesn't affect items 0-4.
In addition to what #Jon Skeet said, another option is to copy the list, leaving out the items you don't want.
List<string> copy = new List<string>(list.Count - indexesToDelete.Count);
for (int index = 0; index < list.Count; index++)
{
if (!indexesToDelete.Contains(index))
copy.Add(list[index]);
}
list = copy;
I am not claiming this is an improvement over Jon's answer, only that it is an alternative. I can imagine some scenerios where this approach may be preferred.

Is it possible to let List collapse after I do removeAt certain times?

Let's say there is a list of List<UInt32>
Thus, :
12|12
23|33
33|22
11|22
I need to remove 0th and 2nd element (List<UInt32>). However, when I try to foreach this list and first remove 0th, the List collapses its elements and 1st becomes 0th now.. so I don't want to delete the wrong element, because my another List<int> includes the positions of elements I want to delete.
Anyway, I thought of doing some algorithm for this, but I wonder if there is already solution for this problem.
Sort the positions list in descending order and remove elements in that order.
foreach (var position in positions.OrderByDescending(x=>x))
list.RemoveAt(position);
Are you able to tell which elements you need to remove based on the elements themselves instead of the index? If so, and you want to change the existing list instead of creating a newly filtered one, use:
list.RemoveAll(x => (whatever - a predicate));
This is more efficient than removing elements one at a time - each element is only moved once. It's also clearer, if the predicate is obvious :)
If you are using C#3.0 (or greater) you can use the LINQ extension method Where to filter your list.
var source = new List<int> { 1, 2, 3, 4, 5 };
var filter = new List<int> { 0, 2 };
var result = source.Where((n, i) => !filter.Contains(i)) // 2, 4, 5
And if you want it back to a List<int> instead of IEnumerable<int>, just use ToList()
var list = result.ToList();
You could create a new collection and adding the items that you don't want to remove and then assign the new collection to the original. That may even be faster than RemoveAt if the indices to be removed are in a hashset/dictionary rather than a list.

Categories