I have a list in C#
List<int> temp = new List<int>(0, 1, 2, 3, 4, 2, 8);
And I would like to make a list of items in temp that satisfy a bool expression, such as
List<int> results = temp.Sort(x > 2);
But .Sort() doesn't exist. The resulting list results would then contain
(3, 4, 6)
Which are the indexes of the values in the original list temp that are greater than 2.
Sorry if this is trivial or has been asked before; I'm new to coding and to SO. Thanks!
EDIT: As some of you have correctly pointed out, I'm don't actually want to sort the list, I just want to filter it. Thanks!
From the output it appears that you need Indices
List<int> temp = new List<int>{0, 1, 2, 3, 4, 2, 8};
var newList = temp.Select((r, i) => new { Index = i, Value = r })
.Where(r => r.Value > 2) //For your condition
.OrderBy(r => r.Value)
.Select(r => r.Index) //For output
.ToList();
This would return you (3, 4, 6)
EDIT: Since the question has been edited and pointed out that sorting the list based on value is not required, in that case OrderBy in the above statement can be left out.
var newList = temp.Select((r, i) => new { Index = i, Value = r })
.Where(r => r.Value > 2) //For your condition
.Select(r => r.Index) //For output
.ToList();
A simple, fast and easy to understand solution would be:
for (int i = 0; i < temp.Count; i++)
if(temp[i] > 2) results.Add(i);
I would like to make a list of items in temp that satisfy a bool expression,
That would be Where:
List<int> temp = new List<int>(0, 1, 2, 3, 4, 2, 8);
List<int> results = temp.Where(x => x > 2);
There are many variations of Select and Where that include the index of items that meet a criteria - if you can be more clear on what you want then you will get better examples.
You need to keep store the index before applying the where clause, or it will be lost.
List<int> temp = new List<int>{ 0, 1, 2, 3, 4, 2, 8 };
List<int> results = temp.Select((x,i) => new { Value = x, Index = i })
.Where(x => x.Value > 2)
.Select(x => x.Index)
.ToList();
You could try this one:
List<int> results = temp.Select((x, index) => new { Index = index, Number = x })
.Where(x=>x.Number > 2)
.Select(x=>x.Index);
Related
For example I have following list
var arr = new List<int> { 1, 4, 4, 4, 5, 3 };
I implemented as:
var res1 = from type in arr
group type by type into ByrdTypes
select new
{
Group = ByrdTypes.Key,
Count = ByrdTypes.Count()
};
var correct = from item in res1
where item.Count == res1.Max(y => y.Count)
select item;
var result = correct.Min(x => x.Group);
This is working solution. But how can I rewrite this in one Linq expression(query)? Thank you.
You could just use OrderBy or OrderByDescending then First or Last
var list = new List<int>() { 1, 4, 4, 4, 5, 3 };
var result = list
.GroupBy(type => type)
.Select(x => new {Group = x.Key, Count = x.Count()})
.OrderByDescending(x => x.Count)
.First();
// The above will get you the group with the highest count
Console.WriteLine(result);
Output
{ Group = 4, Count = 3 }
I have a list let's say {1,1,2,2,3,3,3,4,4,4}. I want to find a List of the elements that occur the most often (it has to be a list as there can be a situation like here that 3 and 4 occur most and I need to get that information. How can I achieve this using LINQ?
var highCountItems = source
.GroupBy(item => item)
.GroupBy(g => g.Count(), g => g.Key)
.OrderByDescending(counts => counts.Key)
.First();
int theCount = highCountItems.Key;
var theItems = highCountItems.ToList();
By Grouping:
var grp = list.GroupBy(i => i).ToList();
int max = grp.Max(c => c.Count());
var most = grp.Where(d => d.Count() == max)
.Select(c => c.Key).ToList();
First you will have to group the numbers followed by ordering them so you will get the most frequently occurring number on the top.
int[] numbers = { 1, 1, 2, 2, 3, 3, 3, 4, 4, 4 };
var groups = numbers.GroupBy(i => i).OrderByDescending(g => g.Count());
foreach (var group in groups)
{
// group.Key -> Represents the number in the list
}
The groups variable will contain all the groups formed from the numbers list ordered by their occurrence, meaning the first group will be the top most occurring group followed by the next. In case of same occurrences, the groups will be ordered by their occurrence in the list for example 3 & 4 have equal occurrences whereas 3 comes first before 4 and hence the group formation will be in same order.
A little complicated
var lst_input = new List<int>(new int[] { 1, 1, 2, 2, 3, 3, 3, 4, 4, 4 });
var result = lst_input.Where(x => lst_input.Max(y => lst_input.Count(z => z == y)) == lst_input.Count(z => z == x)).Distinct().ToList();
But the above code is not effective when dealing with a really big array, since finding max is re-run for each element, and we could distinct the list in the first place. Another more efficient way:
var lst_input = new List<int>(new int[] { 1, 1, 2, 2, 3, 3, 3, 4, 4, 4 });
var tmp = lst_input.Distinct();
var max_val = tmp.Max(y => lst_input.Count(z => z == y));
var result = tmp.Where(x => max_val == lst_input.Count(z => z == x)).ToList();
I have a List<List<int>[]> containing lists items e.g
List<int> a= new List<int>(){ 2, 2, 3, 4, 5};
List<int> b= new List<int>() { 2, 2, 2, 6 };
List<List<int>[]> c = new List<List<int>[]>();
c.Add(new[]{a,b});
I want to check if any of the arrays contained in c have 2 as a value . This is more or less a true or false answer.
So far I can check if a or b contains 2 using the Linq code
var result = a.Any(p=> p==2); // this outputs 2
extending this to the c
var result=c.Any(p=> p.Select(value => value.Contains(2)).First());
// the above code p=> p.Select(value => value.Contains(2)) returns an Enumerable and I take the first one. I'm not positive this is the right way to go about this problem using linq.
Is there a better way of doing this?
If you know how to search in a single list, you should be able to search in list of lists exactly the same way. Just flatten it with SelectMany and use the same criteria.
For your case, if this is for single list:
var result = a.Any(p => p == 2);
then for list of lists it would be:
var result = c.SelectMany(x => x).Any(p => p == 2);
and similar for third level as in your example:
var result = c.SelectMany(x => x).SelectMany(x => x).Any(p => p == 2);
I love PetSerAl's any any any answer but a tiny change
c.Any(x => x.Any(y => y.Contains(2)))
you need something like this:
c.Where(i=>i.Any(x=>x.Contains(2)))
List<int> a = new List<int>() { 2, 2, 3, 4, 5 };
List<int> b = new List<int>() { 2, 2, 2, 6 };
List<List<int>[]> c = new List<List<int>[]>();
c.Add(new[] { a, b });
//Lambda
bool IsValueExists = c.Any(i => i != null && i.Any(i1 => i1.Any(i2=>i2 == 2)));
//OR
//Linq
bool IsValueExists = (from i in c
from i1 in i
from i2 in i1
where i2 == 2
select i2).Any();
c.SelectMany(inner=>inner.SelectMany (i =>i )).Contains(2).Dump();
Using LINQ, can I write a statement that will return an IEnumerable of the indexes of items.
Very simple instance:
{1,2,4,5,3}
would just return
{0,1,2,3,4}
and
{1,2,4,5,3}.Where(num => num == 4)
would return
{2}
It isn't exact code, but it should get the idea across.
var a = new[] {1, 2, 4, 5, 3};
//** First, generates a simple sequence with {0,1,2,3,4}
//** using the 2 parameter lambda select
var sequence1 = a.Select((_, index) => index);
//** Second, gets an array with all indexes where the value is 4.
// We need both value and index for the next line to work.
var sequence2 = a.Select((value, index) => new {value, index});
// Get all indexes where the value is 4
var indexArray = sequence2.Where(x => x.value == 4)
.Select(x => x.index).ToArray();
var numbers = Enumerable.Range(1,10).ToList();
int index = -1;
var indices = numbers.Select(x => i++).ToList();
If you're willing to change up your syntax a bit and use an extension method, the following will work. I'm not keen on it as it creates a new sequence for every call.
var sequence = new[] { 1, 2, 4, 5, 3 };
sequence.Indexer().Select(num => num.Item1); // returns {0,1,2,3,4}
sequence.Indexer().Where(num => num.Item2 == 4).Select(num => num.Item1); // returns {2}
private static IEnumerable<Tuple<int, T>> Indexer<T>(this IEnumerable<T> sequence)
{
return sequence.Select((x, y) => new Tuple<int, T>(y, x));
}
A better way would be to change up the way you're writing it altogether:
var sequence = new[] { 1, 2, 4, 5, 3 };
sequence.Select((num, index) => new { Num = num, Index = index }).Select(num => num.Index); // returns {0, 1,2,3,4}
sequence.Select((num, index) => new { Num = num, Index = index }).Where(num => num.Num == 4).Select(num => num.Index); // returns {2}
The full set of indices just depends on the number of items, not on the values, so you can do this:
IEnumerable<int> indices = Enumerable.Range(0, 5);
If you're dealing with an IEnumerable<T>, you could do the following to get the index of the item matching 4:
IEnumerable<int> values = new[] { 1, 2, 3, 4, 5 };
int indexOf4 = (
values.Select((v, i) => new {v, i})
.FirstOrDefault(vi => vi.v == 4) ?? new {v = 0, i = -1}).i;
This copes with the case where the value source doesn't contain a match (returning -1).
Of course, if you don't mind converting your IEnumerable<T> to a list then you can just call IndexOf:
int indexOf4a = values.ToList().IndexOf(4);
But, I suspect what the question is really looking for is a way to find all the indices for values that match a particular predicate. For example:
IEnumerable<int> big = values.Select((v, i) => new {v, i})
.Where(vi => vi.v > 3)
.Select (vi => vi.i);
which returns the indices of the values > 3: [3, 4].
If the predicate doesn't match any values then you'll get an empty enumerable as the result.
IEnumerable<int> seq = new[] { 1, 2, 4, 5, 3 };
// The indexes of all elements.
var indexes = Enumerable.Range(0, seq.Count());
// The index of the left-most element with value 4.
// NOTE: Will return seq.Count() if the element doesn't exist.
var index = seq.TakeWhile(x => x != 4).Count();
// The indexes of all the elements with value 4.
// NOTE: Be careful to enumerate only once.
int current_index = 0;
var all_indexes =
from e in (
from x in seq
select new { x, Index = current_index++ }
)
where e.x == 4
select e.Index;
You can do it like this:
public static IEnumerable<int> WhereIndices<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
return source.Select(Tuple.Create<T, int>)
.Where(z => predicate(z.Item1)).Select(z => z.Item2);
}
It's an extension method, so put it in a static non-nested class. Use it just like you use Where, that is:
.WhereIndices(num => num == 4)
This should do it. Not sure how efficient it is though..
List<int> list = new List<int>()
{
1,
2,
3,
4,
5
};
var indexes = list.Select(item => list.IndexOf(item));
var index = list.Where(item => item == 4).Select(item => list.IndexOf(item));
This question already has answers here:
Find character with most occurrences in string?
(12 answers)
Closed 7 years ago.
I want to find the Mode in an Array. I know that I have to do nested loops to check each value and see how often the element in the array appears. Then I have to count the number of times the second element appears. The code below doesn't work, can anyone help me please.
for (int i = 0; i < x.length; i ++)
{
x[i]++;
int high = 0;
for (int i = 0; i < x.length; i++)
{
if (x[i] > high)
high = x[i];
}
}
Using nested loops is not a good way to solve this problem. It will have a run time of O(n^2) - much worse than the optimal O(n).
You can do it with LINQ by grouping identical values and then finding the group with the largest count:
int mode = x.GroupBy(v => v)
.OrderByDescending(g => g.Count())
.First()
.Key;
This is both simpler and faster. But note that (unlike LINQ to SQL) LINQ to Objects currently doesn't optimize the OrderByDescending when only the first result is needed. It fully sorts the entire result set which is an O(n log n) operation.
You might want this O(n) algorithm instead. It first iterates once through the groups to find the maximum count, and then once more to find the first corresponding key for that count:
var groups = x.GroupBy(v => v);
int maxCount = groups.Max(g => g.Count());
int mode = groups.First(g => g.Count() == maxCount).Key;
You could also use the MaxBy extension from MoreLINQ method to further improve the solution so that it only requires iterating through all elements once.
A non LINQ solution:
int[] x = new int[] { 1, 2, 1, 2, 4, 3, 2 };
Dictionary<int, int> counts = new Dictionary<int, int>();
foreach( int a in x ) {
if ( counts.ContainsKey(a) )
counts[a] = counts[a]+1
else
counts[a] = 1
}
int result = int.MinValue;
int max = int.MinValue;
foreach (int key in counts.Keys) {
if (counts[key] > max) {
max = counts[key];
result = key;
}
}
Console.WriteLine("The mode is: " + result);
As a beginner, this might not make too much sense, but it's worth providing a LINQ based solution.
x
.GroupBy(i => i) //place all identical values into groups
.OrderByDescending(g => g.Count()) //order groups by the size of the group desc
.Select(g => g.Key) //key of the group is representative of items in the group
.First() //first in the list is the most frequent (modal) value
Say, x array has items as below:
int[] x = { 1, 2, 6, 2, 3, 8, 2, 2, 3, 4, 5, 6, 4, 4, 4, 5, 39, 4, 5 };
a. Getting highest value:
int high = x.OrderByDescending(n => n).First();
b. Getting modal:
int mode = x.GroupBy(i => i) //Grouping same items
.OrderByDescending(g => g.Count()) //now getting frequency of a value
.Select(g => g.Key) //selecting key of the group
.FirstOrDefault(); //Finally, taking the most frequent value