I have an array of integers. I can GroupBy, Sort, and Take the less repeat element:
int [] list = new int[] {0, 1, 1, 0, 2};
var result = list
.GroupBy(a => a)
.Select(g => new {
Number = g.Key,
Total = g.Count()
})
.OrderBy(g => g.Total).Take(1);
Inside a foreach I can retrieve the result, I even have Intellisense for group properties {Number, Total}
foreach (var group in result)
{
// Display key and its values.
Console.WriteLine("Number = {0} Total: {1}", group.Number, group.Total);
}
But I don't like to do a foreach to do that, I prefer to do something like
result.Number or
result[0].Number
But doesn't work. What should be the right way to do it?
You are using Take(1) which still returns an IEnumerable. You probably want to use FirstOrDefault() which does not return an IEnumerable.
.OrderBy(g => g.Total).Take(1);
Then you can use it like result.Number and result.Total.
Your problem is that Take returns IEnumerable, so if you want to fetch only first element, in that case use FirstOrDefault:-
var result = list.GroupBy(a => a)
.Select(g => new
{
Number = g.Key,
Total = g.Count()
})
.OrderBy(g => g.Total).FirstOrDefault();
Then, you can simply say: - result.Number. Please note FirstOrDefault may return null so better check for nulls before accessing any property otherwise you may get Null Reference Exception.
Also, if you are looking for any specific index then you can use ElementAtOrDefault like this:-
var result = list.GroupBy(.....)..OrderBy(g => g.Total);
int SecondNumber = result.result.ElementAtOrDefault(1).Number;
But again be aware of NRE.
Check these Methods:
.FirstOrDefault(); //gets the first element
.Take(n); //gets the first n elements
.Skip(n).FirstOrDefault(); //gets the (n+1)th element
.Skip(n).Take(m); //gets the first m elements after n elements
An anonymous type does not implement IEnumerable<T>, there for you cannot access it via index.
If you only want the very first object you can use First() or FirstOrDefault. If you cast it to an array, you can use an index and then have support for your properties again:
result.FirstOrDefault().Number;
result.ToArray()[1].Number;
Related
So I've got the following code:
string matchingName = "Bob";
List<string> names = GetAllNames();
if (names.Contains(matchingName))
// Get the index/position in the list of names where Bob exists
Is it possible to do this with a couple of lines of code, rather than iterating through the list to get the index or position?
If you have multiple matching instances and want to get all the indices you can use this:
var result = Enumerable.Range(0, names.Count).Where(i => names[i] == matchingName);
If it is just one index you want, then this will work:
int result = names.IndexOf(matchingName);
If there is no matching instance in names, the former solution will yield an empty enumeration, while the latter will give -1.
var index = names.IndexOf(matchingName);
if (index != -1)
{
// do something with index
}
If you want to look for a single match, then IndexOf will suit your purposes.
If you want to look for multiple matches, consider:
var names = new List<string> {"Bob", "Sally", "Hello", "Bob"};
var bobIndexes = names.Select((value, index) => new {value, index})
.Where(z => z.value == "Bob")
.Select(z => z.index);
Console.WriteLine(string.Join(",", bobIndexes)); // this outputs 0,3
The use of (value, index) within Select gives you access to both the element and its index.
I'm trying to order a list (will refer to this list as result) by a value in another list (Redeems).
The result list contains the Redeems list, and I want to order result by the field "SumChosenYear" in the "Redeems" list and get top 20. This is what I've managed to get, and in theory I think it should work.
result = result
.OrderByDescending(input => input.Redeems
.Select(input2 => input2.SumChosenYear)
.ToList())
.Take(20)
.ToList();
However it throws an exception saying "Atleast one object implement IComparable". Why does this happen?
This line:
input.Redeems
.Select(input2 => input2.SumChosenYear)
.ToList()
returns you a List and because List does not implement IComparable you cannot put this lambda inside this overload of OrderByDescending extension.
You have basically two options:
First option
Cretae your custom implementation of IComparer for this list (assuming SumChosenYear property is an int for this purpose):
public class SumChosenYearListComparer : IComparer<List<int>>
{
public int Compare(List<int> x, List<int> y)
{
//Your custom comparison...
}
}
and then use it with this overload of OrderByDescending extension:
var result = result
.OrderByDescending(input => input.Redeems
.Select(input2 => input2.SumChosenYear)
.ToList(), new SumChosenYearListComparer())
.Take(20)
.ToList();
Second option
You can choose which item in this list you want to use in the comparison(maybe the max, min, first or last value or maybe even the sum of all the items).
Assuming you want to comapre using the max value in the list your code could look something like this:
var result = result
.OrderByDescending(input => input.Redeems
.Max(input2 => input2.SumChosenYear))
.Take(20)
.ToList();
We have the list A which contain the random indexes in it. I have another list B which contains the class objects in it. I want to parse list B with the indexes present in list A and find the objects which have name Amar in it using Linq.
For example:
List<int> Indexes = new List<int>(); // This contains the random indexes
List<Student> StuObj = new List<Student>();
Class Student
{
String name;
}
Now I want to parse the list StuObj with the respect to the indexes present in the list Indexes and get the Student object indexes present in the list StuObj where the name is Amar.
You can do that using Linq. The Where has an overload that provides the index of the element:
List<int> indexes = new List<int>() { 5, 1 , 10, 30 };
var results = listB.Where((item, index)=> indexes.Contains(index)
&& item.Name == "Amar")
.Select(x => listB.IndexOf(x)).ToList();
Edit: to get the index of the element in the original listB, you can make use of the IndexOf(T) method.
This should work:
var result = Indexes
.Select(i => StuObj[i])
.Where(s => s.name = "Amar").ToList()
It performs fast index lookup to fetch only required objects. If you know there is only one record, you can use First or FirstOrDefault instead of ToList.
Assuming you have two lists, List indexList and List dataList, you can use select as follows:
indexList.Select(i => dataList[i]);
You should consider what you wish to happen if indexList contains an integer < 0 or > the size of dataList. For example, you could replace invalid entries with null, like:
indexList.Select(i => i < 0 || i >= dataList.Count ? null : dataList[i]);
Or you could filter them out like:
indexList.Where(i => i>=0 && i < dataList.Count).Select(i => dataList[i]);
Or you may know via preconditions that you will never have items in the index list that are out of the range of valid values.
EDIT
Based on the updated question, try this:
dataList.Where((item, index) => indexList.Contains(index) && item.Name == "Amar")
.Select(item => dataList.IndexOf(item));
This takes advantage of the Select and Where overloads that take the index of the item. The Where clause selects the item where the item's index in dataList is in the indexList, and also where the item's Name is Amar. The Select clause then returns the index of the item in the original data list.
Something like this:
var result = listA
.Where(i => i >= 0 && i < listB.Count)
.Select(i => listB[i])
.FirstOrDefault(b => b.Name == "Amar");
Basically you use the value from listA as index of an element of the listB. If you are sure that listA contains only valid indexes, then Where call can be removed.
EDIT: As per updated question, the answer is even easier:
var result = listA
.Where(i => i >= 0 && i < listB.Count && listB[i].Name == "Amar")
.ToList();
I see absolutely no reason to use the linear searching (hence slow) methods Contains and IndexOf as suggested in some other answers.
I have a generic List List[int, myClass], and I would like to find the smallest int value, and retrieve the items from the list that match this.
I am generating this from another LINQ statement
var traysWithExtraAisles = (from t in poolTrays
where t.TrayItems.Select(i=>i.Aisle)
.Any(a=> ! selectedAisles.Contains(a))
select new
{
count= t.TrayItems.Select(i=>i.Aisle)
.Count(a=> !selectedAisles.Contains(a)),
tray=t
}).ToList();
this gives me my anonymous List of [count, Tray], but now I want to figure out the smallest count, and return a sublist for all the counts that match this.
Can anyone help me out with this?
var smallestGroup = traysWithExtraAisles
.GroupBy(x => x.count)
.OrderBy(g => g.Key)
.First();
foreach(var x in smallestGroup)
{
var poolTray = x.tray;
}
You can use SelectMany to "flatten" your list. Meaning, combine all of the lists into one, then take the Min. So;
int minimum = poolTrays.SelectMany(x => x).Min(x => x.TheIntegerIWantMinOf);
Will give you the smallest value contained in the sub lists. I'm not entirely sure this is what you're asking for but if your goal is simply to find the smallest element in the collection then I would scrap the code you posted and use this instead.
Right, I now realise this is actually incredibly easy to do with a bit more fiddling around. I have gone with
int minCount = traysWithExtraAisles.Min(x=>x.count);
var minAislesList = (from t in trayswithExtraAisles
where t.count==mincount
select t).ToList()
I imagine it is probably possible to do this in one statement
You can use GroupBy as answered by Tim... or OrderBy as follow:
var result = traysWithExtraAisles.OrderBy(x=>x.count)
.TakeWhile((x,i)=> i == 0 || x.count == traysWithExtraAisles[i-1]).count;
I have an array of strings called "Cars"
I would like to get the first index of the array is either null, or the value stored is empty. This is what I got so far:
private static string[] Cars;
Cars = new string[10];
var result = Cars.Where(i => i==null || i.Length == 0).First();
But how do I get the first INDEX of such an occurrence?
For example:
Cars[0] = "Acura";
then the index should return 1 as the next available spot in the array.
You can use the Array.FindIndex method for this purpose.
Searches for an element that matches
the conditions defined by the
specified predicate, and returns the
zero-based index of the first
occurrence within the entire Array.
For example:
int index = Array.FindIndex(Cars, i => i == null || i.Length == 0);
For a more general-purpose method that works on any IEnumerable<T>, take a look at: How to get index using LINQ?.
If you want the LINQ way of doing it, here it is:
var nullOrEmptyIndices =
Cars
.Select((car, index) => new { car, index })
.Where(x => String.IsNullOrEmpty(x.car))
.Select(x => x.index);
var result = nullOrEmptyIndices.First();
Maybe not as succinct as Array.FindIndex, but it will work on any IEnumerable<> rather than only arrays. It is also composable.