Check a List<List<int>[]> contains a value using Linq - c#

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();

Related

How get max count with min key from list integer with linq written in one expression

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 }

List of most occurrences of element

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();

How to count how many times exist each number from int[] inside IEnumerable<int>?

I have array of ints(Call him A) and IEnumarable(Call him B):
B - 1,2,4,8,289
A - 2,2,56,2,4,33,4,1,8,
I need to count how many times exist each number from A inside B and sum the result.
For example:
B - 1,2,4,8,289
A - 2,2,56,2,4,33,4,1,8,
result = 1+3+2+1+0
What is elegant way to implement it?
With LINQ it is easy:
int count = A
.Where(x => B.Contains(x))
.Count();
Counts how many times elements from A are contained in B.
As Yuval Itzchakov points out, this can be simplified like this:
int count = A.Count(x => B.Contains(x));
I need to count how many times exist each number from A inside B and sum the result.
You can get both the count and sum as follows
List<int> b = new List<int>() { 1,2,4,8,289 };
List<int> a = new List<int>() { 2,2,56,2,4,33,4,1,8 };
var subset = a.Where(i => b.Contains(i));
var count = subset.Count(); // 7
var sum = subset.Sum(); // 23
Note that I reuse the same Linq expression to get both the count and the sum.
One might be tempted to use a HashSet<int> in place of a List<int> because the .Contains operation is faster. However, HashSet is a set, meaning if the same number is added multiple times, only one copy of that number will remain in the set.
sweet and simple.. one line solution
why dont you try it..
int sum = 0;
A.ToList().ForEach(a=>sum +=B.Count(b=>b==a));
Console.Write(sum);
you can sweap the A/B it will still work
With Linq you can do like this
var B = new List<int>{ 1, 2, 4, 8, 289 };
var A = new List<int> { 2, 2, 56, 2, 4, 33, 4, 1, 8 };
var repetitionSum = B.Select(b => A.Count(a => a == b)).Sum(); //result = 7
And if you want, you can get the individual repetition list like this
var repetition = B.Select(b => A.Count(a => a == b)).ToList();
// { 1, 3, 2, 1, 0 }
It is not clear if you want to know the occurrences of each number or the final count (your text and your example code differ). Here is the code to get the number of appearances of each number
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
int[] a = new []{1,2,3};
int[] b = new []{1,2,2,3};
Dictionary<int, int> aDictionary = a.ToDictionary(i=>i, i => 0);
foreach(int i in b)
{
if(aDictionary.ContainsKey(i))
{
aDictionary[i]++;
}
}
foreach(KeyValuePair<int, int> kvp in aDictionary)
{
Console.WriteLine(kvp.Key + ":" + kvp.Value);
}
}
}

Sort list index by value

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);

How to efficiently prune a list based on "is-subset" condition?

Let's suppose I am given Dictionary<int, List<int>> and I want to prune it using the following condition
an item should be removed from the dictionary if there exists an itemLarger != item in the dictionary such that item.Value.Union(new[] { item.Key }) is a subset of itemLarger.Value.Union(new[] { itemLarger.Key })
That is, each item in the dictionary will be represented by a list of numbers obtained by appending the item's key to the item's value and I want to get rid of those items which are represented by a subset of some other item's representation.
Example:
var testResult = new Dictionary<int, List<int>>
{
{ 2, new[] { 3, 4 }},
{ 3, new[] { 2, 4 }},
{ 1, new[] { 2, 3, 4 }},
{ 4, new[] { 2, 3 }}
};
In this case, the only element left in the list would be {1, {2, 3, 4}}
I can't seem to find some elegant way to do it, since
GroupBy does not allow me to specify which element in particular should be used as the key when I have two that should be groupped
Distinct does not allow me to specify, in case two elements are not distinct, which of them should be kept in the list
Of course it is doable in a trivial way. I wonder if there is some nice one.
Thank you for any ideas.
I don't think this will be much different from the "trivial" way you meant, but here's a LINQ solution:
var sets = testResult
.Select(x => new { Key = x.Key, Set = new HashSet<int>(x.Value.Concat(new[] { x.Key })) })
.ToList();
var res = sets.Where(s => sets.Any(x => x.Set.IsSupersetOf(s.Set) && x.Key != s.Key));
var keysToRemove = res.Select(x => x.Key);
This might not be the most effective way but it's short and kind of readable.
var test = new Dictionary<int, List<int>>
{
{ 2, new List<int> { 3, 4 }},
{ 3, new List<int> { 2, 4 }},
{ 1, new List<int> { 2, 3, 4 }},
{ 4, new List<int> { 2, 3 }}
};
var res = test.Where(n => !test.Any(m => m.Key!=n.Key && n.Value.Intersect(m.Value).Count()==n.Value.Count) );
In my solution I check for each element x in testResult if this element is subset of any other element in testResult. If it isn't, this element pass 'where' filter in linq expression. Two last lines are conversion of result from list representation to dictionary representation.
var listResult =
(from x in testResult
where (from y in testResult
where !x.Value.Except(y.Value).Any() && x.Key != y.Key
select y).Count() == 0
select x).ToList();
var dictionaryResult = new Dictionary<int, List<int>>();
listResult.ForEach(x => dictionaryResult.Add(x.Key, x.Value));
Edit:
We could write it even shorter:
testResult = testResult.Where(x =>
(from y in testResult
where !x.Value.Except(y.Value).Any() && x.Key != y.Key
select y).Count() == 0).ToDictionary(x => x.Key, x => x.Value);

Categories

Resources