Find collection containing the average of several collections with LINQ - c#

Simple (not for me yet I guess) LINQ: I have a List of arrays, and I want to get a collection containing the average of each column. Something like:
var myCollection = new List<double[]>();
myCollection.Add(new []{1,2,3,4,5});
myCollection.Add(new []{3,4,5,6,7});
// Your answer --> {2,3,4,5,6}

Like so?
var myCollection = new List<double[]>();
myCollection.Add(new double[]{1,2,3,4,5});
myCollection.Add(new double[]{3,4,5,6,7});
var qry = (from col in Enumerable.Range(0, myCollection.Min(arr => arr.Length))
select myCollection.Average(arr => arr[col])).ToList();
Original answer from when the question referred to a "2 dimensional array":
How about (note - you may need to reverse col and row depending on how you choose to orient your data):
int[,] data = {{0,1,2},{3,4,5}};
var qry = (from col in Enumerable.Range(0, data.GetLength(0))
select new {
col, avg = Enumerable.Range(0, data.GetLength(1))
.Select(row => data[col, row]).Average()
}).ToList();
foreach(var result in qry) {
Console.WriteLine("{0}: {1}", result.col, result.avg);
}
Or if you just want the averages (not the anon-type):
var qry = (from col in Enumerable.Range(0, data.GetLength(0))
select Enumerable.Range(0, data.GetLength(1))
.Select(row => data[col, row]).Average()).ToList();

Since you have modified the question, changing the 2 dimensional array to List<double[]>, another solution is:
var result = myCollection.Aggregate((arr1, arr2) => arr1.Zip(arr2, (x, y) => (x + y) / 2).ToArray())

Related

How to distinct and count the duplicates inside a listbox?

I'm trying to make a listbox where i can add items to it using datagridview, the thing is i want to determine which item is duplicate and how many times it duplicate.
item1
item1
item2
item2
item2
output item1=2, item2=3
Here is the one that i tried which shows the last item that have been duplicate
int count = 0;
for (int i = 0; i < listBox1.Items.Count; i++)
{
var s = listBox1.Items[i].ToString();
if (s.StartsWith(listfood))
{
if (s == listfood)
{
++count;
}
}
}
MessageBox.Show(count.ToString());
Try
var duplicateItems = listBox1.Items.GroupBy(x => x.ToString())
.Where(x => x.Count() > 1)
.Select(x => new { Value = x.Key, Count = x.Count() })
.ToList();
using System.Linq;
// ...
var duplicates = listBox1.Items.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => new { ItemName = y.Key, Occurrences = y.Count() })
.ToList();
foreach (var duplicate in duplicates)
MessageBox.Show($"{duplicate.ItemName}: {duplicate.Occurrences}");
This solution uses LINQ to query the listBox1's Items collection and filter out any data we don't care about.
First, we use GroupBy to sort the items. Then, Where will filter out any items in the collection that only exist once. Select allows us to "project" the items remaining in the filtered collection into a "new form" (we use an anonymous type with an ItemName and Occurrences property to track the names of the duplicates and the number of times it appears in the collection).
Finally, ToList converts the collection from an IEnumerable<string> to aListtype.ToListis optional depending on how you plan on usingduplicates. In fact, my example doesn't need to callToListbecause aforeachloop can iterate over anIEnumerable` collection.
I know the Answers above will definitely work, but i can't understand it and make it work. This one works for me, where i transfer values of listbox to an array and check the duplicates inside that array.
var list = new List<string>();
foreach(var item in listBox1.Items)
{
list.Add(item.ToString());
}
var r = from b in list
group b by b into g
let count = g.Count()
orderby count descending
select new { Value = g.Key, Count = count };
foreach(var x in q)
{
MessageBox.Show("value: " + b.Value + " Count:" + b.Count);
}
Found my answer here

C# Linq Find all indexes of item in List<int> within another List<int>

I have a List looks like:
List<int> List1= new List<int>(){3,4,5};
and another looks like:
List<int> List2 = new List<int>(){1,2,3,4,5,6};
How can I use Linq to get an array of all of the indices of List1 from List2 like below:
var ResultList = {2,3,4};
var ResultList = List1.Select(x => List2.IndexOf(x));
This is a longer solution but prevents a nested loop through the array which may be faster if the arrays are huge (but slower if the arrays are small).
List<int> List1= new List<int>(){3,4,5};
List<int> List2 = new List<int>(){1,2,3,4,5,6};
var lookup = new Dictionary<int, int>();
for(var i=0; i<List2.Count; i++) {
lookup[List2[i]] = i;
}
List<int> Result = List1.Select(i => {
int index;
return lookup.TryGetValue(i, out index) ? index : -1;
}).ToList();
You can also do the overloaded version of Select statement to select the Value and return the Index:
var result = List2.Select((a, b) => new {Value = a, Index = b})
.Where(x => List1.Any(d => d == x.Value))
.Select(c => c.Index).ToArray();
If your List2 contains more than one instance of a List1 value (or Equality) type, then you can use the indexed overload of Select to find all the duplicates:
var List1= new List<int>(){3,4,5};
var List2 = new List<int>(){1,2,3,4,5,6,1,2,3,5};
var result = List2.Select((x, idx) => Tuple.Create(x, idx))
.Where(t => List1.Contains(t.Item1))
.Select(x => x.Item2)
// 2,3,4,8,9
or better, using C#7 Value Tuples
List2.Select((x, idx) => (X:x, Idx:idx))
.Where(t => List1.Contains(t.X))
.Select(x => x.Idx);
(.IndexOf returns just the first index found in the target)

How to group by and count similar lists in a List<List<String>>

I have a list of a list of strings:
List<List<String>> pChain;
It might have repeated lists of strings (two list of strings are equal if they have the same strings in the same order). I want to have the count of each distinct list in the main list. I tried:
var results = (from t in pChain
group t by new { t }
into g
select new
{
g.Key,
Count = g.Count(),
}).OrderByDescending(x => x.Count).ToList();
foreach (var v in results)
{
ListViewItem lv = listView2.Items.Add(v.Key.ToString());
lv.SubItems.Add(v.Count + "");
}
But it doesn't group similar list of strings into one list and doesn't count them.
You can use SelectMany + Distinct:
var allDistinctItems = pChain.SelectMany(list => list).Distinct();
If you want the count use int countOfDistinctItems = allDistinctItems.Count();.
If you want a dictionary you could use:
Dictionary<string, int> itemCounts = pChain.SelectMany(list => list)
.GroupBy(item => item)
.ToDictionary(g => g.Key, g => g.Count());
You can check if a list of lists contains an specific list by iterating through its elements and checking if they are SequenceEqual(). You should be able to remove the duplicate lists with this:
for(int i = 0; i < pChain.Count(); i++)
{
// If the amount(Count) of SequenceEqual lists in pChain for the current iteration
// of pChain (pChain[i]) is > 1
if (pChain.Count(l => l.SequenceEqual(pChain[i])) > 1)
pChain.RemoveAt(i);
}
Thus the amount of distinct lists would be:
int count = pChain.Count();
You can put the code above into a single linQ line this way:
pChain.Select((x, y) => new { list = x, Index = y }).ToList()
.ForEach(l1 => {
if (pChain.Count(l2 => l2.SequenceEqual(l1.list)) > 1)
pChain.RemoveAt(l1.Index);
});
I tried Aggregate function to join the strings of the inner list to a string resulted from concatenating them. Then applied the GroupBy to this list.
Dictionary<string, int> itemCounts =
pChain.Select(list => list.Aggregate((i, j) => j + '/' + i))
.GroupBy(item => item).OrderByDescending(x => x.Key)
.ToDictionary(g => g.Key.ToString(), g => g.Count());
foreach (var v in itemCounts)
{
ListViewItem lv = listView2.Items.Add(v.Key.ToString());
lv.SubItems.Add(v.Value + "");
}

Getting count of duplicate items in a List [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I am trying to get the count for the most common duplicate item in a list.
So far, I have:
List<string> brandList = new List<string>();
which contains 5 different soft drink brands, and the count is 100. I need to find out which brand has the most duplicates in the list and count how many duplicates there are.
Presuming that your pseudo code actually was:
List<Brand> brandList=new List<Brand>();
// fill list
and your Brand class either overrides Equals+getHashCode or has a property like BrandID which is the identifier. N youow want to get the count of the most popular brand, you can use LINQ:
var mostPopularBrand = brandList.GroupBy(b => g.BrandID)
.OrderByDescending(g => g.Count())
.Select(g => new { BrandID = g.Key, Count = g.Count()})
.First();
Console.WriteLine("Most poular brand: {0} Count: {1}",
mostPopularBrand.BrandID, mostPopularBrand.Count);
Update: If it's actually a List<string>(question was edited):
var mostPopularBrand = brandList.GroupBy(str => str)
.OrderByDescending(g => g.Count())
.Select(g => new { Brand = g.Key, Count = g.Count()})
.First();
Your code doesn't compile. Providing that you mean List<String> as a storage of brands:
var ListbrandList = new List<String>() {
"Cola",
"Juice",
"Cola",
"Water",
"Milk",
"Water",
"Cola",
};
var result = ListbrandList
.GroupBy(item => item)
.Select(item => new {
Name = item.Key,
Count = item.Count()
})
.OrderByDescending(item => item.Count)
.ThenBy(item => item.Name);
String report = String.Join(Environment.NewLine, result
.Select(item => String.Format("{0} appears {1} time(s)", item.Name, item.Count)));
you'll have report as
Cola appears 3 time(s)
Water appears 2 time(s)
Juice appears 1 time(s)
Milk appears 1 time(s)
var result = brandList
.Distinct()
.GroupJoin(brand,
k => k,
b => b,
(k, b) => new { BrandName = k, Count = b.Count() });
// An usage could be...
foreach (var r in result)
{
Debug.WriteLine("{0} Brand has {1}", r.BrandName, r.Count);
}
Without LinQ:
var result = new Dictionary<string, int>();
foreach (var brand in brandList)
{
if (!result.ContainsKey(brand))
{
var count = brandList.FindAll(x => x.Equals(brand)).Count;
result.Add(brand, count);
}
}
foreach (var r in result)
{
Console.WriteLine("{0} Brand has {1}", r.Key, r.Value);
}
You can try to do group using LINQ by Elements and calculate count
var groupedList = from l in ListbrandList
group l by l into grp
select new { key = grp.Key, cnt = grp.Count()};
Then you will have group by key (Element) and value (Count)
Something like this maybe:
var res = brandList.GroupyBy(x => x)
.Select(x => new {Key = x.Key, Count = x.Count});
Now you have a list containing the actual drink-number and the count for this number.
EDIT: Getting the brand with most count is now easy, e.g. by using:
var mostPopular = res.Single(x => x.Count == res.Max(y => y.Count));
EDIT2: Without LINQ the following might work, which is way longer and more complicated:
// get the count for every brand
Dictionary<string, int> res = new Dictionary<string, int>();
foreach(var x in brands)
{
if (!res.ContainsKey(x)) res[x] = 0;
res[x]++;
}
// now get the max count
int currentMax = 0;
string key = "";
foreach (var kv in res)
{
if (kv.Value > currentMax)
{
currentMax = kv.Value;
key = kv.Key;
}
}
Now the key should contain the brand with highest Count.
To count element with specific value in a list use :
int quantity = lst.Count(r => r == "Cola");
Example :
List<string> lst = new List<string>()
{
"Sprite",
"Cola",
"Sprite",
"Sprite",
"Cola",
"Sprite",
"Sprite",
"Cola",
"Pepsi",
"Sprite",
"Pepsi",
"Sprite",
};
string[] popularBrands = { "Cola", "Pepsi" };
int[] quantities = new int[popularBrands.Length];
for (int i = 0; i < popularBrands.Length; i++)
{
quantities[i] = lst.Count(r => r.ToUpper() == popularBrands[i].ToUpper());
Console.WriteLine("{0} : {1}", popularBrands[i], quantities[i]);
}
Output
Cola : 3
Pepsi : 2
P.S.
About this code r => r.ToUpper() == popularBrands[i].ToUpper() :
r is variable that holds a value from our list (that are taken one by one). We also use ToUpper() to make sure that our check is case insensitive.
So we basically loop through the collection taking values out of it one by one. Each time we put value to r variable and check if this variable satisfies condition. If so - we count it, if not - we just move to next value.

Adding Lists Together

I have multiple lists of strings, IList<string>, that I want to consolidate in one list showing distinct string and count for each item (like a dictionary). what is the most efficient way to do this?
LINQ (certainly the most efficient in terms of code to type and maintain; the overall performance will be about the same as any other approach):
if the lists are in separate variables:
var qry = from s in listA.Concat(listB).Concat(listC) // etc
group s by s into tmp
select new { Item = tmp.Key, Count = tmp.Count() };
if the lists are all in a parent list (of lists):
var qry = from list in lists
from s in list
group s by s into tmp
select new { Item = tmp.Key, Count = tmp.Count() };
Then if you really want a list:
var resultList = qry.ToList();
Dictionary<string, int> count = new Dictionary<string, int>();
foreach(IList<int> list in lists)
foreach(int item in list) {
int value;
if (count.TryGetValue(item, out value))
count[item] = value + 1;
else
count[item] = 1;
}
List<List<string>> source = GetLists();
//
Dictionary<string, int> result = source
.SelectMany(sublist => sublist)
.GroupBy(s => s)
.ToDictionary(g => g.Key, g => g.Count())

Categories