In my C# code I have a list List<Tuple<int,string>>. I want to select/convert this to a List<Type>. I want to avoid iterating my list of tuple and insert in other list. Is there any way to do this? Maybe with LINQ?
You cannot change type of list. You only can create new list of another type and fill it with converted values from your list. I suggest to use List<T>.ConvertAll method which exists exactly for this purpose:
List<Tuple<int, string>> tuples = new List<Tuple<int, string>>();
// ...
List<YourType> types =
tuples.ConvertAll(t => new YourType { Foo = t.Item1, Bar = t.Item2 });
You haven't shown this type, but i assume that it contains an int- and a string-property:
List<MyType> result = tupleList
.Select(t => new MyType { IntProperty = t.Item1, StringProperty = t.Item2 })
.ToList();
another option: List.ConvertAll:
List<MyType> result = tupleList.ConvertAll(t => new MyType { IntProperty = t.Item1, StringProperty = t.Item2 });
This presumes that your List<Type> is actually a List<CustomType> (I've called it MyType).
I want to avoid iterating my list of tuple and insert in other list.
LINQ does not avoid loops, it hides them just.
Related
For simple example, I have a class like this:
public class MyClass {
public string name;
public int item1;
public int item2;
}
and a List(MyClass), how do I query the list to create List(int) of both fields item1 and item2? It seems it should be simple but I am struggling a long time.
var result = myList.Select(i => i.item1).ToList() //selects only one field
I know i could use anonymous type but since both item1 and item2 are integers I dont need any new type.
var result = myList.Select(i => new { i.item1, i.item2} ).ToList() //dont need new type, both are integers
how to create list of int? Or did I misunderstood what the anonymous types do?
If you don't like using anonymous types, you could always use a Tuple
var result = myList.Select(i => Tuple.Create(i.item1, i.item2) )
But since both item1 and item2 are integers, you can use an array:
var result = myList.Select(i => new[] { i.item1, i.item2 } )
This will result in a IEnumerable<int[]>. If you want an IEnumerable<int> (with each record's item1 and item2 together in one result set), use SelectMany:
var result = myList.SelectMany(i => new[] { i.item1, i.item2 } )
If you want a flattened list you can do:
List<int> ints = myList.SelectMany(i => new[] { i.item1, i.item2 }).ToList();
if you want to keep the values together you can create a tuple:
List<Tuple<int, int>> pairs = myList.Select(i => Tuple.Create(i.item1, i.item)).ToList():
You can use the following expression for example to create a list containing both items fro all elements of the original list myList.
var result = myList.Select(i => item1).Concat(myList.Select(i => i.item2));
I have a method that, must return a list of objects, but i don't know how!
my problem is converting(or maybe casting)groupdResult to IList.
internal IList<MyClass> MyMethod()
{
IList<MyClass> result=new List<MyClass>();
IList<MyClass> rawData = this.GetRawDatas();
foreach (MyClass item in rawDatas){
// do somthings
MyClass balancedData = new MyClass();
if(some conditions){
result.Add(balancedData);
}
}
var groupdResult = result.GroupBy(x => x.MyField).ToList();
return groupdResult;
}
Think about it: The result is either going to be a list of groups or a list of ungrouped objects. I believe that what you want is actually just a sorted list:
return result.OrderBy(x => x.MyField).ToList();
It's not the List/IList you're having trouble with. It's the fact that GroupBy does not return MyClass.
GroupBy returns an IGrouping, so the line
var groupdResult = result.GroupBy(x => x.MyField).ToList();
returns a List< IGrouping< MyClass > >.
Changing
var groupdResult = result.GroupBy(x => x.MyField).ToList();
to
var groupdResult = result.GroupBy(x => x.MyField).SelectMany(g=>g.ToList).ToList();
Solve the problem
I have a class that is defined like this:
class A
{
int contractID;
string name;
string blah;
etc...
}
Multiple ClassA are stored stored in List(). I and to create a List based off all the ContractID's in List. Is there a way in LINQ to be able to do this instead of iterating through List()?
You can use the Select extension method to create a projection of the contractID. Like:
var listOfClass = new List<ClassA>(); //Or however you get your list.
var contractIDs = listOfClass.Select(x => x.contractID).ToList();
var onlyContractIDs = myList.Select(x => x.contractID).ToList()
List<ClassA> input = ...;
List<int> output = input.Select(a => a.contractID).ToList();
Select is a generic method. Explicitly specified, it would be Select<ClassA, int>, specifying the input and output types.
The ToList() at the end converts from an IEnumerable<int> to a List<int>, and it does the iteration over the input list now, rather than when the IEnumerable<int> is enumerated.
If you have a List you can make a List with LINQ like this
List<int> contractIDs = mycollection.Select(a => a.ContractID).ToList();
var list = new List<ClassA>();
...
list.Select(a => a.ContractID);
I have 3 .net Lists items, I need to merge them all into one, to order them and bind them to a datagrid. However, I need a way of indicating which original list each item came from, so that I can identify this in the datagrid (change color or font etc).
Can anyone suggest the best way to do this?
List<Foo> list1 = new List<Foo>();
List<Foo> list2 = new List<Foo>();
List<Foo> list3 = new List<Foo>();
var query = list1.Select(foo => new { foo, list = "list1" })
.Concat(list2.Select(foo => new { foo, list = "list2" }))
.Concat(list3.Select(foo => new { foo, list = "list3" }))
.OrderBy(item => item.foo); // whatever you need to order by
Expand the properties as needed.
Assuming that your lists contains items of classes that you can amend I'd suggest that you add a property to those classes that keeps track of which type of the 3 it is. Either as an enum or possibly a reference to the actual list that contained it if you might need to refer back.
If you're not able to do that but assuming that they do contain a name property or similar and it's a readonly grid, a very ugly way would be to add a specific prefix/postfix to the name that says where it came from and then just remove that prefix/postfix before showing it on the screen.
Simple solution, assuming you don't want to modify the original class, or it's a primitive, you can use anonymous types:
var resultList = list1.Select(value => new {value, list = list1})
.Concat(list2.Select(value => new {value, list = list2})
.Concat(list3.Select(value => new {value, list = list3})))
.ToList();
I'd go with something like this:
List<object> list1 = new List<object>();
List<object> list2 = new List<object>();
List<object> list3 = new List<object>();
List<KeyValuePair<int, object>> mergedList = new List<KeyValuePair<int, object>>();
mergedList.AddRange(list1.Select(obj => new KeyValuePair<int, object>(1, obj)));
mergedList.AddRange(list2.Select(obj => new KeyValuePair<int, object>(2, obj)));
mergedList.AddRange(list3.Select(obj => new KeyValuePair<int, object>(3, obj)));
The better solution though, would be to add a property to your object that is some kind of enumeration that tells you something about the object itself. The lists themselves are metadata of some sort - list1 is a list of X, not just a list, so all of it's elements should have some kind of notion of X.
I have a field object and I create a list of fields:
class Field {
string objectName;
string objectType;
string fieldName;
string fieldValue;
//constructor...
}
List<Field> fieldList = new List<Field>();
Suppose I wanted to query this list to return a collection of distinct object names (to then be inserted into a checkedlistbox. How would I go about doing that?
I imagine some LINQ magic can manage this?
The expression should return a List of distinct object names from the list as defined. I converted it to a list since the docs for the CheckedListBox DataSource property indicated that it needs to implement IList or IListSource, not merely IEnumerable.
((ListControl)cbListBox).DataSource = fieldList.Select( f => f.objectName )
.Distinct()
.ToList() );
If accessing the checkedListBox as a ListControl doesn't give access to the DataSource (sometimes the docs lie), you could try:
cbListBox.Items.AddRange( fieldList.Select( f => f.objectName )
.Distinct()
.ToArray() );
Either of these work
Using var
1) var fieldNameCollection = from f in fieldList select f.FieldName;
2) Lambda syntax
var fieldNameCollection = fieldList.Select(f => f.FieldName);
Alternately, instead of using var, you can also use
IEnumerable fieldNameCollection = fieldList.Select(f => f.FieldName);
var q = from Field f in fileldList select f.objectName;
chkBoxList.DataSource = q.Distinct();