I have a function that returns IEnumerable<IEnumerable<string>>. I want to use this function, building on the basic IEnumerable, assigning it to a List<List<string>>. This would be easy if I just had one dimension (i.e. one collection), and would be solved by using the ToList() method - but how do i do this for an IEnumerable<IEnumberable<string>> without iterating through each of the items?
You could use Enumerable.SelectMany
For example(from MSDN)
PetOwner[] petOwners =
{ new PetOwner { Name="Higa, Sidney",
Pets = new List<string>{ "Scruffy", "Sam" } },
new PetOwner { Name="Ashkenazi, Ronen",
Pets = new List<string>{ "Walker", "Sugar" } },
new PetOwner { Name="Price, Vernette",
Pets = new List<string>{ "Scratches", "Diesel" } } };
// Query using SelectMany().
IEnumerable<string> query1 = petOwners.SelectMany(petOwner => petOwner.Pets);
Probably the best resource on this topic(J.Skeet):
Reimplementing LINQ to Objects: Part 9 - SelectMany
Here's another example with a List<List<string>> like in your question:
var lists = new List<List<string>>();
lists.Add(new List<String>(new[] { "A", "B", "C" }));
lists.Add(new List<String>(new[] { "D", "E", "F", "G" }));
lists.Add(new List<String>(new[] { "H", "I", "J", "K", "L" }));
var all = lists.SelectMany(i => i);
String allLetters= String.Format("All letters: {0}",String.Join(",",all));
I 'm assuming you have some kind of IEnumerable<IEnumerable<T>>. You can flatten it using something like this: YourList.SelectMany(x => x).
Related
I have a list of strings List{"X", "W", "C", "A", "D", "B" } and I have another list of strings List{"A", "B", "C", "D"} that tells how the first list must be ordered. But the second list has only four items in it. I would like my first list to be ordered like this:
A, B, C, D, X, W. Actually the last two letters X and W doesn't matter how they are ordered, but they should be at the end of the list.
I tried this:
var newList = list1.OrderBy(i=>list2.IndexOf(i));
but this gives me only four items.
Your current code will give you 6 items. However, it will put X and W in the beginning since they have an index of -1 in list 2.
Here is how to fix that:
var list1 = new List<string> {"X", "W", "C", "A", "D", "B"};
var list2 = new List<string> {"A", "B", "C", "D"};
var newList = list1.OrderBy(x =>
{
var index = list2.IndexOf(x);
if (index == -1)
index = Int32.MaxValue;
return index;
})
.ToList();
One more way along with others.
List<string> list1 = new List<string>() {"X", "W", "C", "A", "D", "B" } ;
List<string> list2 = new List<string>() { "A", "B", "C", "D" } ;
var newList = list2.Intersect(list1)
.Union(list1.Except(list2));
Check Demo
This should work:
var newList = list1.OrderBy(i => {
var x = list2.IndexOf(i);
if(x == -1)
return int.MaxValue;
return x; });
Result (from LinqPad):
Could someone tell me how I can declare a 2D and 3D List, with the elements specified in one statement? I do not want to have them declared later. The List objects are meant to be unchanged.
This is what I am trying to have with a 3D list, but it is not correct:
List<string[][]> List_3D = new List<string[][]> { { new string[][] { new string[] { "A", "B", "C" },
new string[] { "D", "E", "F" } },
new string[] { "1", "2", "3" },
new string[] { "4", "5", "6" } };
All you want is to declare them in one statement, like this?
public List<String> foo = new List<String> { "a", "b", "c" };
public List<List<String>> foo2D = new List<List<string>>
{
new List<String> {"a", "b", "c"},
new List<String> {"d", "e", "f"}
};
public List<List<List<String>>> foo3D = new List<List<List<string>>>
{
new List<List<String>>
{
new List<String> {"a", "b", "c"},
new List<String> {"d", "e", "f"}
},
new List<List<String>>
{
new List<String> {"g", "h", "i"},
new List<String> {"j", "k", "l"}
}
};
Edit
just curious, how do you declare an outer List with inner string[][]
inside?
Basically the same concept, except replace the list with arrays:
public List<String[][]> fooString2D = new List<String[][]>
{
new String[][]
{
new String[] {"a", "b", "c"},
new String[] {"d", "e", "f"}
},
new String[][]
{
new String[] {"g", "h", "i"},
new String[] {"j", "k", "l"}
}
};
What is incorrect about your specific code:
It has an extra { right in the beginning
It is missing the second new string[][] declaration
It needs an extra } at the end.
I think what you're looking for is object initialization. See Object and Collection Initializers.
Here is a simple example:
List<int> myList = new List<int>
{
1,
2,
3
};
I came up with this, using LINQ:
records.RemoveAll(x =>
!(x.MyList.Contains(values[0]) || x.MyList.Contains(values[1]) || x.MyList.Contains(values[2]) || ... )
);
records is a List<CustomObject>, that has a List<string> MyList
values is an OrderedDictionary, though it could easily be a Dictionary<string,string> instead, if there is a solution that doesn't require accessing it by index.
My problem with this code is that I don't know the size of values ahead of time, and can't hardcode it like this. Is there a way to use a for or foreach loop here? Or, how else can I achieve this line of code?
I think it will be something like
records.RemoveAll(x =>
!(values.Any(v=>x.MyList.Contains(v)))
);
Try this:
var values = new OrderedDictionary()
{
{ "A", null },
{ "B", null },
{ "C", null },
{ "D", null },
{ "E", null },
};
var records = new List<CustomObject>
{
new CustomObject{ Id = 1, MyList = new List<string>(){ "A", "B" }},
new CustomObject{ Id = 2, MyList = new List<string>(){ "C", "F" }},
new CustomObject{ Id = 3, MyList = new List<string>(){ "G", "H" }}
};
records.RemoveAll(record => !record.MyList.Any(item => values.Contains(item)));
foreach (var record in records)
{
Console.WriteLine("Id={0}, MyList={1}",
record.Id, String.Join(", ", record.MyList.ToArray()));
}
This works as well...
records.Except(values.Select(v => v.Value)).ToList().ForEach(a => records.Remove(a.ToString())) ;
Let's say I have a list of unknown number of elements in string value, I want to divide it to n subarray or lists (n could be any int, for example n=3), what is best way to do it?
note: the number of elements in each group is not necessary to be equal
LINQ GroupBy and Select methods can help:
var list = new List<string>() { "A", "B", "C", "D", "E", "F", "G" };
int groupCount = 3;
var subLists = list.Select((s, i) => new {Str = s, Index = i}).
GroupBy(o => o.Index % groupCount, o => o.Str).
Select(coll => coll.ToList()).
ToList();
This code will result in subLists containing a list of three List<string> collections: {"A", "D", "G"}, {"B", "E"} and {"C", "F"}. In order to achieve that I based my grouping on element indices in the original list (there is an overload for Select method that lets you do that, see link above). You can use some other logic to select the key.
In my example subLists is a List<List<string>>. If you need an array, use ToArray where appropriate.
EDIT: using modulo operation for grouping may not be a good idea if you care about the way values are distributed between lists. Probably the better option is to do it this way:
var list = new List<string>() { "A", "B", "C", "D", "E", "F", "G" };
int groupCount = 3;
int maxPerGroup = (int)Math.Ceiling((double)list.Count / groupCount);
var subLists = list.Select((s, i) => new {Str = s, Index = i}).
GroupBy(o => o.Index / maxPerGroup, o => o.Str).
Select(coll => coll.ToList()).
ToList();
This will produce the following result: {"A", "B", "C"}, {"D", "E", "F"}, {"G"} which may be more sane way to distribute the values.
Bottom line is, you can achieve what you need by using GroupBy and Select methods, just provide the correct grouping logic that is suitable for your domain.
alternately, you can do it in linq like
var n = 4;
var i = 0;
var list = new List<string> { "a", "b", "c", "d", "e", "f", "g" };
var res = list.GroupBy(x => Math.Ceiling((double)++i / n)).Select(x=>x.Select(y=>y).ToList()).ToList();
Console.Write(res);
write this in Console program or Linqpad and change values of n to see the effect
I have an array structured like this:
{"nick", "sender", "message"}
arranged into a List<string[]>.
What I want to do, is to search the list using the 0 index value of the array (ie nick).
I tried using:
list.Find(i => i[0].Equals(nick))
but this doesn't seem to do anything.
How would I do this?
I think this what you want
list.Where(i => i[0] == "nick")
It will return a IEnumerable<string[]> where nick if the first element in each string[]
list.Where(x => x[0].Equals(nick));
I guess you're after:-
list.Find(i => i.Equals("nick"))
I'm also guessing that this isn't what you mean....
Perhaps you have something more like this:-
static void Main(string[] args)
{
var test = new List<string[]>() {
new String[3] { "a", "b", "b" },
new String[3] { "a", "c", "c" },
new String[3] { "b", "b", "c" },
new String[3] { "a", "d", "d" },
new String[3] { "x", "y", "z" }
};
var foundFirst = test.Find(i => i[0].Equals("a"));
var foundAll = test.Where(i => i[0].Equals("a"));
}