I am looking for a better data structure or method to simply replace an object in an dynamic array. It seems like list is the choice, however I read and notice that the performance of RemoveAt and Insert is not as good as I had hoped.
Let me elaborate on what I am trying to achieve:
List1
List item 1
List item 2
List item 3
List2
List item 1
List item 2
Null
Both list uses the same object types. I want to replace the null list item of List2 with List1[1] -- List item 1 clone. I use a clone so the value of the copied list item is a separate instance.
I also want to replace list item 2 of List2 with a clone of list item 1 of List2.
Here is some example code of what I am trying to achieve:
projCraneVertices.RemoveAt(projCraneVertices.Count - 4);
projCraneVertices.Insert((projCraneVertices.Count - 3), realCraneVertices[botPoint].clone());
projCraneVertices.RemoveAt(projCraneVertices.Count - 3);
projCraneVertices.Insert((projCraneVertices.Count - 2), projCraneVertices[botPoint].clone());
projCraneVertices.RemoveAt(projCraneVertices.Count - 2);
projCraneVertices.Insert((projCraneVertices.Count - 1), realCraneVertices[topPoint].clone());
projCraneVertices.RemoveAt(projCraneVertices.Count - 1);
projCraneVertices.Insert((projCraneVertices.Count), projCraneVertices[topPoint].clone());
I also want to replace list item 2 of List2 with a clone of list item
1 of List2.
Well, you can do it simpler like this:
proCraneVertices[2] = realCraneVertices[1].Clone();
From what I can understand, you want a Replace method. Try this extension:
public static class Extensions
{
public static void Replace<T>(this IList<T> list, int index, T item)
{
list[index] = item;
}
}
Call like:
List<int> ints = new List<int>() { 1, 2, 3 };
List<int> ints2 = new List<int>() { 4, 5, 6 };
ints.Replace(0, ints2[0]);
The above will make the first list - 4, 2, 3.
using List of T will solve you problem of removeAt and inset this uses Array under the hood and will expose some good functions to you that will help to ridoff these anoing methods.
you can use some of function provided by List like below.
Replace // Replact the item from one item to another item
List of T Class
Related
I'm new in c#. I just want to ask if it is possible to insert a list object inside a c# list just like in python? C# addrange only insert multiple item at once but not a list object.
For example:
lst = [[1,2,3],[4,5,6],[7,8,9]]
Yes, but is much more verbose than python.
As some comments already answered, you can use a List of List to create something like your python example:
List<List<int>> listOfLists = new List<List<int>>() { new List<int>() {1,2,3}, new List<int>() {4,5,6}, new List<int>() {7,8,9}};
You can also make a list of different objects just declaring it a List of Objects:
List<object> listOfObjects = new List<object>();
listOfObjects.Add(new List<int>() { 1, 2, 3 }); // Adding list of int
listOfObjects.Add("text"); // Adding string
listOfObjects.Add(new float[] { 1.42f, 51.7f}); // Adding array of float
listOfObjects.AddRange(listOfObjects); // Duplicating all the elements of listOfObjects
listOfObjects.AddRange(listOfLists); // Adding all elments of the list listOfLists
List AddRange is just a way of adding many elements at once inside a list.
I'm trying to write a method for a project which takes any number of lists as parameters, and returns a new list containing terms which ALL of those lists share. I have functional code, but I'd much prefer to use the params keyword rather than having to create a list of lists which holds all the lists I want to compare.
static List<T> Shared<T>(List<T> first, List<T> second)
{
List<T> result = new List<T>();
foreach (T item in first)
if (second.Contains(item) && !result.Contains(item)) result.Add(item);
return result;
}
static List<T> Shared<T>(List<List<T>> lists)
{
List<T> result = lists.First();
foreach (List<T> list in lists.Skip(1))
{
result = Shared<T>(result, list);
}
return result;
}
Is my current code, which works fine comparing two lists, but in order to compare more than two lists I have to either create a new list like:
List<int> nums1 = new List<int> { 1, 2, 3, 4, 5, 6 };
List<int> nums2 = new List<int> { 1, 2, 3 };
List<int> nums3 = new List<int> { 6, 5, 3, 2 };
List<int> listOfLists = Shared<int>(new List<List<int>> {nums1, nums2, nums3});
foreach (int item in listOfLists)
Console.WriteLine(item);
//Writes 2 and 3
etc. I would really wish to just be able to use Shared(list1, list2, list3, list4...) instead, even if this code is already somewhat functional. Currently any attempts to use a params version complains that "No overload for method 'Shared' takes N arguments"
Also I know my code could probably be done more efficiently, so I'd be glad to see suggestions on that too but primarily I need to get my head around why using params isn't working - if it's even possible.
Are you looking for this?
static List<T> Shared<T>(params List<T>[] lists)
The params parameter must always have an array type, but it can be an array of Lists.
It can be done quiet easily:
using System.Linq;
// ..
static List<T> Shared<T>(params List<T>[] lists)
{
if (lists == null)
{
throw new ArgumentNullException("lists");
}
return Shared(lists.ToList());
}
Building on the response of #Selman22 who proposed the method signature, you could alternatively use this LINQ query, to achieve the desired result.
static List<T> Shared<T>(params List<T>[] lists)
{
return
lists.Skip(1).Aggregate( // Skip first array item, because we use it as a seed anyway
lists.FirstOrDefault(), // Seed the accumulator with first item in the array
(accumulator, currentItem) => accumulator.Intersect(currentItem).ToList()); // Intersect each item with the previous results
}
We skip the first item that is being used as the seed for the accumulator, and do an intersect with the accumulator for each item in the given params array, since only the items that are contained in ALL the lists are kept in the accumulator result.
To test it out, you can use
Shared(nums1, nums2, nums3).ForEach(r => Console.WriteLine(r));
With a list you can do:
list.AddRange(otherCollection);
There is no add range method in a HashSet.
What is the best way to add another ICollection to a HashSet?
For HashSet<T>, the name is UnionWith.
This is to indicate the distinct way the HashSet works. You cannot safely Add a set of random elements to it like in Collections, some elements may naturally evaporate.
I think that UnionWith takes its name after "merging with another HashSet", however, there's an overload for IEnumerable<T> too.
This is one way:
public static class Extensions
{
public static bool AddRange<T>(this HashSet<T> source, IEnumerable<T> items)
{
bool allAdded = true;
foreach (T item in items)
{
allAdded &= source.Add(item);
}
return allAdded;
}
}
You can also use CONCAT with LINQ. This will append a collection or specifically a HashSet<T> onto another.
var A = new HashSet<int>() { 1, 2, 3 }; // contents of HashSet 'A'
var B = new HashSet<int>() { 4, 5 }; // contents of HashSet 'B'
// Concat 'B' to 'A'
A = A.Concat(B).ToHashSet(); // Or one could use: ToList(), ToArray(), ...
// 'A' now also includes contents of 'B'
Console.WriteLine(A);
>>>> {1, 2, 3, 4, 5}
NOTE: Concat() creates an entirely new collection. Also, UnionWith() is faster than Concat().
"... this (Concat()) also assumes you actually have access to the variable referencing the hash set and are allowed to modify it, which is not always the case." – #PeterDuniho
so i have a list where i need to add new values constantly but when i do i need to increment it and insert it in between two values.
List<int> initializers = new List <int>();
initializers.Add(1);
initializers.Add(3);
so initializers would have 1, 3 values.
i would then process a new set of numbers. the initializers will need to have the values.
1, 5, 3, 7
and if i process another set of numbers it should become
1, 9, 5, 13, 3, 11, 7, 15
i know how to properly generate the new values inserted, i just need some help on inserting it in between the existing values of the initializers without having to add 2 or 3 more loops to move the values' positions.
List<int> initializers = new List <int>();
initializers.Add(1);
initializers.Add(3);
int index = initializers.IndexOf(3);
initializers.Insert(index, 2);
Gives you 1,2,3.
Use List<T>.Insert:
initializers.Insert(index, value);
You can just use List.Insert() instead of List.Add() to insert items at a specific position.
For those who are looking for something more complex (inserting more than one item between 2 values, or don't know how to find the index of an item in a list), here is the answer:
Insert one item between 2 values is dead easy, as already mentioned by others:
myList.Insert(index, newItem);
Insert more than one item also is easy, thanks to InsertRange method:
myList.InsertRange(index, newItems);
And finally using following code you can find the index of an item in list:
var index = myList.FindIndex(x => x.Whatever == whatever); // e.g x.Id == id
Another approach, if there is a computationally viable way of sorting the elements, is:
list.Insert(num);
// ...
list.Insert(otherNum);
// Sorting function. Let's sort by absolute value
list.Sort((x, y) => return Math.Abs(x) - Math.Abs(y));
I'd like to use Remove() method on list of lists, but it's not working for me.
Simple example should say everything:
List<List<int>> list = new List<List<int>>();
list.Add(new List<int> { 0, 1, 2 });
list.Add(new List<int> { 1, 2 });
list.Add(new List<int> { 4 });
list.Add(new List<int> { 0, 1, });
list.Remove(new List<int> { 1, 2 });
If I use RemoveAt(1) it works fine but Remove() not.
It is obviously the same reason that this code returns false:
List<int> l1 = new List<int>();
List<int> l2 = new List<int>();
l1.Add(1);
l2.Add(1);
bool b1 = l1 == l2; // returns False
bool b2 = l1.Equals(l2); // returns False too
So it seems to me that I cannot simply compare two lists or even arrays. I can use loops instead of Remove(), but there must be easier way.
Thanks in advance.
The problem is that List<T> doesn't override Equals and GetHashCode, which is what List<T> will use when trying to find an item. (In fact, it will use the default equality comparer, which means it'll use the IEquatable<T> implementation if the object implements it, and fall back to object.Equals/GetHashCode if necessary). Equals will return false as you're trying to remove a different object, and the default implementation is to just compare references.
Basically you'd have write a method to compare two lists for equality, and use that to find the index of the entry you want to remove. Then you'd remove by index (using RemoveAt). EDIT: As noted, Enumerable.SequenceEqual can be used to compare lists. This isn't as efficient as it might be, due to not initially checking whether the counts are equal when they can be easily computed. Also, if you only need to compare List<int> values, you can avoid the virtual method call to an equality comparer.
Another alternative is to avoid using a List<List<int>> in the first place - use a List<SomeCustomType> where SomeCustomType includes a List<int>. You can then implement IEquatable<T> in that type. Note that this may well also allow you to encapsulate appropriate logic in the custom type too. I often find that by the type you've got "nested" collection types, a custom type encapsulates the meaning of the inner collection more effectively.
First approach:
List<int> listToRemove = new List<int> { 1, 2 };
list.RemoveAll(innerList => innerList.Except(listToRemove).Count() == 0);
This also removes the List { 2, 1 }
Second approach (preferred):
List<int> listToRemove = new List<int> { 1, 2 };
list.RemoveAll(innerList => innerList.SequenceEqual(listToRemove));
This removes all lists that contain the same sequence as the provided list.
List equality is reference equality. It won't remove the list unless it has the same reference as a list in the outer list. You could create a new type that implements equality as set equality rather than reference equality (or you do care about order as well?). Then you could make lists of this type instead.
This simply won't work because you're tying to remove a brand new list (the new keyword kind of dictates such), not one of the ones you just put in there. For example, the following code create two different lists, inasmuch as they are not the same list, however much they look the same:
var list0 = new List<int> { 1, 2 };
var list1 = new List<int> { 1, 2 };
However, the following creates one single list, but two references to the same list:
var list0 = new List<int> { 1, 2 };
var list1 = list0;
Therefore, you ought to keep a reference to the lists you put in there should you want to act upon them with Remove in the future, such that:
var list0 = new List<int> { 1, 2 };
listOfLists.Remove(list0);
They are different objects. Try this:
List<int> MyList = new List<int> { 1, 2 };
List<List<int>> list = new List<List<int>>();
list.Add(new List<int> { 0, 1, 2 });
list.Add(MyList);
list.Add(new List<int> { 4 });
list.Add(new List<int> { 0, 1, });
list.Remove(MyList);
You need to specify the reference to the list you want to remove:
list.Remove(list[1]);
which, really, is the same as
list.RemoveAt(1);