.NET / C# - Convert List to a SortedList - c#

What is the best way to convert a List to SortedList? Any good way to do it without cycling through it? Any clever way to do it with an OrderBy()?
WRAP UP
Please read all answers and comments.

Do you mean:
you have a List<T> and wish it to be sorted in place?
you have a List<T> and wish to create another 'list' which is itself sorted
you have a List<T> and wish to make a SortedList<T,T> where the key is the same as the value
Assuming input:
var x = new List<int>() { 3, 2, 1 };
1 is trivial
x.Sort();
2 is trivial
// sx is an IOrderedEnumerable<T>, you can call ToList() on it if you want
var sx = x.OrderBy(i => i);
3 is trivial with a copy
var s = new SortedList<int,int>(t.ToDictionary(i => i));
and more efficiently:
var s = new SortedList<int,int>();
foreach (var i in x) { s[i] = [i]; }
I can't see why you would want to do 3 but there you go.

var list = new List<string>();
var sortedList = new SortedList<string, string>(list.ToDictionary(s => s));
Now I have no clue how efficient this is, but it's one line of code :) Also, in this example I just used the string itself as the selector. In a real scenario, you should know ahead of time what you'd like to use as a selector.

Understand that a List<T> is a smart array, and a SortedList<T, U> is a key/value binary tree. Since there's no relationship between their structures, there can't possibly be a more effective way to do it rather than simply taking each element from the list and putting it into the tree.
If you mean "sorted list" instead of "SortedList," then it's trivial to sort your list via either List.Sort() or an appropriate OrderBy().

List unsortedPersons = new List();
// ... Populate unsortedPersons ...
var sorted = from person in unsortedPersons
orderby person.Name
select person;
The LINQ gives you an ISortedEnumerable i believe, which may be good enough for your purposes.

Related

How alter List<int> with LINQ ForEach

I have a List<int> myInts and want to multiply all with 10. I want to use linq (not foreach loop).I tryed this but nothing happend:
List<int> myInts = new List<int>() { 1, 2, 3 };
myInts .ForEach(act => act=act*10);
Of what do I have to take care in the .ForEach(...) part? And yes, I want to use ForEach if it is somehow possible.
Probably its simple, but I cant see it, I apoligize. Thank you all!
This creates a new instance of List.
myInts = myInts.Select(p=>p*10).ToList();
Another and simpler solution:
list = list.ConvertAll(i => i * 10);
"Nothing happens" because reassigning to the local variable (act) has no effect in the caller (ForEach) - C# is Call By Value (except for ref/out parameters).
To modify the list in place, simply use a standard for-each over the indices (which I find readable and upfront of the side-effect intent):
var myInts = new List<int>() { 1, 2, 3 };
for (var i = 0; i < myInts.Count; i++) {
myInts[i] = myInts[i] * 10;
}
To perform the operation and create a new list/sequence (which can be re-assigned to the same variable), see IEnumerable.Select which is a map transformation.
From MSDN documentation:
Modifying the underlying collection in the body of the Action<T> delegate
is not supported and causes undefined behavior.
So, you need to project your exisistin List into a new one, or you need to use a for loop if you must modify the List "in place"
Regards
What is happening is that you are getting a value copy of the int to your the lambda, which so you won't be able to change the 'external' int.
How about projecting a new list?
List<int> myInts = new List<int>() { 1, 2, 3 };
myInts = myInts.Select(act => act*10).ToList();
To use a .Select or .ConvertAll are good solutions.
But my intention was to let "ForEach" return an alterd list.
I found out, over msdn documentation, that this isnĀ“t possible because ForEach is a void type and has no returntype.
This kind of action works if I would have objects in my List instead of ints. Then I would be able to use the "void" Method to change the properties of my objects.
Do you mean like this ?
List<int> _tempList = new List<int>();
myInts.ToList().ForEach(x => _tempList.Add(x * 10));
try this:
Enumerable.Range(0, myInts.Count).ToList().ForEach(i => myInts[i] = myInts[i] * 10);

Combine 5 List<object> into one List<object>

I have a 5 lists with the same objects in them. I just want to combine them all with there properties intact into one bigger list.
I have thought of a way to do it, but I think there is better ways.
List<object> blah = new List<object>
foreach(object item in ObjectList1)
{
blah.Add(item);
}
If you know a better way to do this let me know, Thanks in Advance!
You could use either List<T>.AddRange() or Linq:
foreach(var list in myLists)
bigList.AddRange(list);
Use Enumerable.Concat().
List<object> blah = ObjectList1
.Concat(ObjectList2)
.Concat(ObjectList3)
// ...
.ToList();
var result = ObjectList1.Concat(ObjectList2).Concat(ObjectList3).
Concat(ObjectList4).Concat(ObjectList5).ToList()
This function...
static IEnumerable<T> Combine<T>(params IEnumerable<T>[] sources) {
return sources.SelectMany(s => s);
}
...can be used like this:
List<object> l1 = ... ;
List<object> l2 = ... ;
List<object> l3 = ... ;
List<object> l4 = ... ;
List<object> l5 = ... ;
var result = Combine(l1, l2, l3, l4, l5).ToList();
BTW, omit ToList if the result doesn't actually need to be a List.
(This will of course work with any number of lists, not just 5.)
Or, if you only need to do it once and don't want to introduce a whole new function just for that:
var result = new[] { l1, l2, l3, l4, l5 }.SelectMany(l => l).ToList();
Or, if you care about performance more than readability, do this to avoid memory re-allocations on list resizes:
var result = new List<object>(l1.Count + l2.Count + l3.Count + l4.Count + l5.Count);
result.AddRange(l1);
result.AddRange(l2);
result.AddRange(l3);
result.AddRange(l4);
result.AddRange(l5);
This code from your question:
List<object> blah = new List<object>
foreach(object item in ObjectList1)
{
blah.Add(item);
}
... could be more concise if you use AddRange:
List<object> blah = new List<object>
blah.AddRange(ObjectList1);
So you can either call AddRange 5 times or concat the 5 lists and pass the result to AddRange.
It's not clear what exactly you mean by "with all their properties intact", but if it means that your other lists are lists of different more specific types than object, then no, you can't create a single list that will give you strongly-typed access to the members of the lists.
EDIT
It seems that "with all their properties intact" means that the objects in the new list will have the same property values as the objects in the old list. And of course they will, since they are the same objects! The lists don't really contain the objects, after all, they contain references to the objects (because object is a reference type). The new list contains copies of the references, not copies of the objects.
I don't know what you are trying to do here. Maybe you should cast the object to a specific object. The code looks correct to me, but it is little weird.
For readability I'd suggest...
List<object> blah = new List<object>
blah.AddRange(ObjectList1);
blah.AddRange(ObjectList2);
blah.AddRange(ObjectList3);
blah.AddRange(ObjectList4);
Try
ObjectList1.Concat(ObjectList2).Concat(ObjectList3).Concat(ObjectList4).Concat(ObjectList5).ToList()`

How to extract (in C#) a specific attribute from every element of a List, and get a new List of these attributes?

We begin with a List<X>. Every object of X has an attribute x of type Y. Could you propose an elegant way to construct a List which is composed of the Z.x for every element Z of some List<X>?
I'm sure "manual" iteration over List<X> isn't necessary. Thanks for any advice.
If this is List<T>, then:
var newList = oldList.ConvertAll(item => item.x);
or with LINQ:
var newList = oldList.Select(item => item.x).ToList();
Note that in C# 2.0 the first version might need the generic type mentioned explicitly:
List<Y> newList = oldList.ConvertAll<Y>(delegate (X item) { return item.x; });
(but that is actually 100% identical to the first line)
There is also a static Array.ConvertAll which behaves similarly, but for arrays.

Deleting item from a List<Type>

This is how I remove an item from a List. Is this the right way? Is there any cleaner/faster way to achieve this.
List<ItemClass> itemsToErase = new List<ItemClass>();
foreach(ItemClass itm in DS)
{
if(itm.ToBeRemoved)
itemsToErase .Add(itm);
}
foreach(ItemClass eraseItem in itemsToErase)
{
DS.Remove(eraseItem );
}
EDIT: DS is of type List<ItemClass>
EDIT: Have one more doubt. What if DS is a LinkedList<ItemClass>. There is no RemoveAll() for that.
There is List.RemoveAll() which takes a delegate where you can add your comparison function.
E.g.:
List<ItemClass> itemsToErase = new List<ItemClass>();
itemsToErase.RemoveAll( itm => itm.ToBeRemoved );
You can use the RemoveAll() method:
DS.RemoveAll(x => x.ToBeRemoved);
This is a O(n) operation, your code is O(n^2).
This methods avoids a lot of copies in the orginal List but has a greater memory consumption.
List<ItemClass> newList = new List<ItemClass>(originalList.Count);
foreach(var item in originalList) {
if (!item.ToBeRemoved)
newList.Add(item);
}
originalList = newList;
Not really, the logic remains the same no matter how you do it. You cannot iterate over and modify a collection at the same time. It looks cleaner with LINQ:
var list = new List<int> { 1, 2, 3, 4, 5 };
var except = new List<int> { 3, 4 };
var result = list.Except(except);
Hope this helps.
edit: Even list.RemoveAll(...) has to maintain two lists internally to do it.
edit2: Actually svick is right; after looking at the implementation, RemoveAll is fastest.
use this method
DS.RemoveAll(x => x.ToBeRemoved);
Your code is a common solution to the problem and is fine. Especially if there are only a few items to be removed.
As others have suggested you can also create a new list containing the items you want to keep and then discard the old list. This works better if most items are going to be removed and only a small number kept.
When picking either of these methods keep in mind that both require the allocation of a new list object. This extra memory allocation probably isn't an issue but might be, depending on what the rest of the code is doing.
As others have mentioned there is also the RemoveAll method. This is what I would use, it is neat, clear and as efficient as anything using a list can be.
The last option is to use an index to loop through the collection. EG.
(Sorry for the VB, I use it more often than C# and didn't want to confuse by getting the syntax wrong)
Dim i as Integer
Do While i<DS.Count
If DS.Item(i).ToBeRemoved Then
DS.RemoveAt(i)
Else
i+=1
End If
Loop

C# Array, How to make data in an array distinct from each other?

C# Array, How to make data in an array distinct from each other?
For example
string[] a = {"a","b","a","c","b","b","c","a"};
how to get
string[]b = {"a","b","c"}
Easiest way is the LINQ Distinct() command :
var b = a.Distinct().ToArray();
You might want to consider using a Set instead of an array. Sets can't contain duplicates so adding the second "a" would have no effect. That way your collection of characters will always contain no duplicates and you won't have to do any post processing on it.
var list = new HashSet<string> { };
list.Add("a");
list.Add("a");
var countItems = list.Count(); //in this case countItems=1
An array, which you start with, is IEnumerable<T>. IEnumerable<T> has a Distinct() method which can be used to manipulate the list into its distinct values
var distinctList = list.Distinct();
Finally,IEnumerable<T> has a ToArray() method:
var b = distinctList.ToArray();
I think using c# Dictionary is the better way and I can sort by value using LINQ

Categories