private static void A(){
List<int[]> list = new List<int[]>();
int[] a = {0,1,2,3,4};
int[] b = {5,6,7,8,9};
list.Add(a);
list.Add(b);
List<int> list2 = new List<int>();
// list2 should contain {0,1,2,3,4,5,6,7,8,9}
}
How would i convert my List<int[]> list into a List<int> so that all the int[] arrays become one giant list of numbers
It looks like you might be looking for LINQ .SelectMany method.
A quote from MSDN:
Projects each element of a sequence to an IEnumerable and flattens
the resulting sequences into one sequence
List<int> list2 = list.SelectMany(l => l).ToList();
If you want numbers to be ordered in a specific order you could use .OrderBy before executing the query (which will be executed when we call .ToList)
List<int> list2 = list.SelectMany(l => l).OrderBy(i => i).ToList();
What about?
var list2 = a.Concat(b).ToList();
I would use the aggregate function. It is better when you have bigger collection.
List<int> list2 = list.Aggregate(new List<int>(), (ag, l) => { ag.AddRange(l); return ag; });
Related
The below list providing a collection of integers. My requirement is to return sequence values are like first 1,2,3,4,5. once the sequence gets less than or equal 1. fetching will be stopped. I could use for loop to do this operation, but I need to do this using LINQ Extension method. Thanks
If I pass 1, then the result should be like 1,2,3,4,5
If I pass 2, then the result should be like 2,3,4,5
If I pass 3, then the result should be like 3,4,5
List<int> list=new List<int>();
list.Add(1);---------
list.Add(2);---------
list.Add(3);---------
list.Add(4);---------
list.Add(5);---------
list.Add(1);
list.Add(2);
list.Add(3);
var result = list.TakeWhile((item, index) => item > list[0] || index == 0);
You can simply use a loop:
List<int> list2 = new List<int>()
for(int i=0;i<list.Count;i++)
if(i==0 || list[i]>list2[i-1])
list2.Add(list[i]);
I have two lists:
List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};
I want do to something like
var newData = data1.intersect(data2, lambda expression);
The lambda expression should return true if data1[index].ToString() == data2[index]
You need to first transform data1, in your case by calling ToString() on each element.
Use this if you want to return strings.
List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};
var newData = data1.Select(i => i.ToString()).Intersect(data2);
Use this if you want to return integers.
List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};
var newData = data1.Intersect(data2.Select(s => int.Parse(s));
Note that this will throw an exception if not all strings are numbers. So you could do the following first to check:
int temp;
if(data2.All(s => int.TryParse(s, out temp)))
{
// All data2 strings are int's
}
If you have objects, not structs (or strings), then you'll have to intersect their keys first, and then select objects by those keys:
var ids = list1.Select(x => x.Id).Intersect(list2.Select(x => x.Id));
var result = list1.Where(x => ids.Contains(x.Id));
From performance point of view if two lists contain number of elements that differ significantly, you can try such approach (using conditional operator ?:):
1.First you need to declare a converter:
Converter<string, int> del = delegate(string s) { return Int32.Parse(s); };
2.Then you use a conditional operator:
var r = data1.Count > data2.Count ?
data2.ConvertAll<int>(del).Intersect(data1) :
data1.Select(v => v.ToString()).Intersect(data2).ToList<string>().ConvertAll<int>(del);
You convert elements of shorter list to match the type of longer list. Imagine an execution speed if your first set contains 1000 elements and second only 10 (or opposite as it doesn't matter) ;-)
As you want to have a result as List, in a last line you convert the result (only result) back to int.
public static List<T> ListCompare<T>(List<T> List1 , List<T> List2 , string key )
{
return List1.Select(t => t.GetType().GetProperty(key).GetValue(t))
.Intersect(List2.Select(t => t.GetType().GetProperty(key).GetValue(t))).ToList();
}
int[] OrderedListToFollow = {1,2,4,5}
int[] ListB = {2,3,4,8,9}
Based on the two lists above I need to sort ListB based on the order defined in OrderedListToFollow. Since 3,8,9 are not part of the OrderedListToFollow those can appear in any order, so the acceptable solutions could have any of the following :
int[] ListB = {2,4,3,8,9}
int[] ListB = {2,4,8,3,9}
int[] ListB = {2,4,9,3,8}
I tried doing this as follows but it does not order it :
ListB = ListB.OrderBy(id => OrderedListToFollow.ToList().IndexOf(id)).ToArray();
EDIT
The order above works but it places the items not present in OrderedListToFollow first and then the remaining.
The problem with your sorting method is that the IndexOf method returns -1 if the item is not found. Thus, all your items which exist "outside" the given ordering scheme are placed at the beginning of the collection because they get an index of -1.
You could try using a conditional to return the index if found and the current index otherwise:
var c = ListB.Count();
ListB = ListB
.OrderBy(id => OrderedListToFollow.Contains(id)
? OrderedListToFollow.ToList().IndexOf(id)
: c + 1 // This will always pace invalid objects at the end
);
As noted, it was already working apart from putting the results at the beginning. To fix this, I'd add an extension method:
public static int IndexOfOrMax(this IEnumerable<T> source, T item)
{
int index = source.IndexOf(item);
return index == -1 ? int.MaxValue : index;
}
Also note that you don't need to call ToList on OrderedListToFollow - currently you're calling that a lot, which is very inefficient. With the above extension method in place, you can use:
int[] orderedListToFollow = {1,2,4,5};
int[] listB = {2,3,4,8,9};
listB = listB.OrderBy(id => orderedListToFollow.IndexOfOrMax(id)).ToArray();
How about something like this:
int[] OrderedListToFollow = {1,2,4,5};
int[] ListB = {2,3,4,8,9};
List<int> ListC = new List<int>();
ListC.AddRange(OrderedListToFollow.Where(p => ListB.Contains(p)));
ListC.AddRange(ListB.Where(p => !OrderedListToFollow.Contains(p)));
This will give you a result like this :
2
4
3
8
9
You can do this using Join and Except, the benefit being that they're both ~O(n) operations (due to both using Hashtables in their implementations). This snippet hinges on the assumption that OrderedListToFollow is indeed ordered.
int[] OrderedListToFollow = new[]{1,2,4,5};
int[] ListB = new[]{3,4,8,2,9};
var existing = from o in OrderedListToFollow
join l in ListB on o equals l
select l;
var other = ListB.Except(OrderedListToFollow);
var result = existing.Concat(other);
Basically I have a list containing all items. Then I have a string containing the IDs I want to grab out from the list, to do this I split the string into an Int array and later use this and LINQ to get the items I want from the list
Like this :
List<T> lstAllList = Model.getAllItems();
string stringIDs = "8,9,12,11,7";
int[] intArray = stringIDs.Split(',').Select(n => Convert.ToInt32(n)).ToArray();
List<T> lstLimitedList = (from r in lstAllList where intArray.Contains(r.id) select r).ToList();
Which works great.
But the issue here is that I want to have my list ordered in the same way as the string of IDs is, i.e 8,9,12,11,7 like in this example.
But the returned list from the LINQ sorts it by the id by default, so the returned list is 7,8,9,11,12.
Is there a way to prevent it from sorting it like this or is there a way to sort the new list with my int array?
Sure, just sort by the index of the ID in the array:
string stringIDs = "8,9,12,11,7";
int[] intArray = stringIDs.Split(',').Select(n => Convert.ToInt32(n)).ToArray();
var lstLimitedList = (
from r in lstAllList
where intArray.Contains(r.id)
orderby Array.IndexOf(intArray, r.id) // <--------
select r).ToList();
Simply getting the elements one at a time may be faster than trying to resort. (Anyone willing to calculate the O() costs?)
List<T> lstLimitedList = new List<T>();
foreach(int id in intArray)
{
lstLimitedList.Add(lstAllList.Where(item => item.id = id));
}
You could also use intArray.ForEach() if you're a LINQ maniac, but this is much easier to read. ;)
Try to rotate your query. Under word rotate I mean start with intArray and use join. Something like this:
List<T> lstLimitedList = (
from id in intArray
join item in lstAllList on id equals item.Id
select item).ToList();
Id use the intersect extension method with provided by LINQ!
int[] array ={ 8,9,12,11,7} // or your result from your split on string;
List<int> array2 = new List<int> { 8,9,12,11,7 } // your model.GetAllItems;
// Call Intersect extension method.
var intersect = array.Intersect(array2);
// Write intersection to screen.
foreach (int value in intersect)
{
Console.WriteLine(value); // Output: 8,9,12,11,7
}
Bit cleaner for me
Stop overusing LINQ guys. In this case linq is a total overkill. A much simpler and better performance-wise solution is the following:
string a = "8,9,12,11,7";
List<int> list = new List<int>();
string[] splitted = a.Split(',');
for (int i = 0; i < splitted.Length; i++)
{
list.Add(int.Parse(splitted[i]));
}
Which a single loop and without sorting etc.
I know how to combine 2 lists together in C#, but suppose I have an IEnumerable of objects, each with a list. How do I create 1 huge list, concatenating all of the lists.
I basically want to do the following in Linq (more elegant)
//FakeObject has a list property
IEnumerable<FakeObject> objects = ...;
List<int> hugeList = new List<int>();
foreach(FakeObject object in objects)
{
List<int> list = object.list;
foreach(int i in list)
{
hugeList.Add(i)
}
}
Use SelectMany to flatten a collection of collections into one list:
var hugeList = objects.SelectMany(o => o.list);
or for an actual list:
List<int> hugeList = objects.SelectMany(o => o.list).ToList();