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
Related
I'm working on a WPF application, and at one point, I have to get/show all the duplicates from the string list. (With the duplicated strings name and the number of how many of that same string is in the list)Like this for example: "The list contains the String 'Hello' 3 times." So far, I'm getting the string's name successfully but I can't manage to get the correct number of times it is presented in the list.
This is my code so far:
List<String> answerData = new List<String>();
using (MySqlCommand command = new MySqlCommand(query2, conn))
{
using (MySqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
answerData.Add(reader.GetString(0));
}
}
}
var duplicates = answerData
.GroupBy(i => i)
.Where(g => g.Count() > 1)
.Select(g => g.Key);
foreach (var d in duplicates)
{
MessageBox.Show(""+ d + duplicates.Count().ToString()); //Here I tried to get the number
//with Count() but it doesn't work as I thought it would.
}
What should I add/change to get the result I want?
EDIT
As suggested changed my code to the following:
var duplicates = answerData
.GroupBy(i => i)
.Where(g => g.Count() > 1);
foreach (var d in duplicates)
{
MessageBox.Show(d.Key + " " + d.Count().ToString());
}
And now it works smoothly.
Thank you everyone!
Store the actual groups instead of the keys in duplicates:
var duplicates = answerData
.GroupBy(i => i)
.Where(g => g.Count() > 1);
You could then iterate through the groups:
foreach (var d in duplicates)
{
MessageBox.Show(d.Key + " " + d.Count().ToString());
}
This example counts, i.e. iterates, each group twice. Alternatively, you could store objects that contain both the Key and the Count as suggested by #HimBromBeere.
You just need to return the number within your Select:
var duplicates = answerData
.GroupBy(i => i)
.Select(g => new { Key = g.Key, Count = x.Count() })
.Where(x => x.Count > 1);
Notice that I changed the order of your statements to avoid a duplicate execution of g.Count().
You can do something like this
you need to use Dictionary for performance reasons
List<String> answerData = new List<String>();
Dictionary<string,int> map = new Dictionary<string, int>();
foreach (var data in answerData)
{
if (map.ContainsKey(data))
{
map[data]++;
}
else
{
map.Add(data, 1);
}
}
foreach (var item in map)
{
if (item.Value > 1)
{
Console.WriteLine("{0} - {1}", item.Key, item.Value);
}
}
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 + "");
}
I need to index the item list with its position after grouping
var result = from i in items
group i by i.name into g
select new { groupname = g.Key,
index = //need to get the index of the item
};
How to get the item index of a list using linq/lambda?
I'm not 100% sure what you're trying to achieve, but I would definitely advice to use methods instead of syntax-based query.
var results = items.GroupBy(x => x.name)
.Select((g, i) => new { product = g.Key, index = i });
Or if you'd like to get indexes from source lift for all items within every group:
var results = items.Select((x, i) => new { x, i })
.GroupBy(x => x.x.name)
.Select(g => new {
product = g.Key,
indexes = g.Select(x => x.i).ToList()
});
var idx = 0;
var result = from i in items
group i by i.name into g
select new { product = g.Key,
index = idx++
};
I have a list of file names (targetFileList), some of which are duplicates (ex. I have two files called m4.txt). The following statement finds the duplicated filenames and adds them to another list (currentTargetFiles):
currentTargetFiles = targetFileList.FindAll(item => item == baselineFilename);
As is, this line is returning a list of strings (filenames), which is good, but I also need their index value. Is there some way to modify it so that it also returns the indices of the files?
Well, here is my answer to "find the duplicate names and their indices". It might not fit the presented problem exactly, as there is no baselineFilename considered - but that is covered by other answers. YMMV.
var names = new [] {"a", "a", "c", "b", "a", "b"};
var duplicatesWithIndices = names
// Associate each name/value with an index
.Select((Name, Index) => new { Name, Index })
// Group according to name
.GroupBy(x => x.Name)
// Only care about Name -> {Index1, Index2, ..}
.Select(xg => new {
Name = xg.Key,
Indices = xg.Select(x => x.Index)
})
// And groups with more than one index represent a duplicate key
.Where(x => x.Indices.Count() > 1);
// Now, duplicatesWithIndices is typed like:
// IEnumerable<{Name:string,Indices:IEnumerable<int>}>
// Let's say we print out the duplicates (the ToArray is for .NET 3.5):
foreach (var g in duplicatesWithIndices) {
Console.WriteLine("Have duplicate " + g.Name + " with indices " +
string.Join(",", g.Indices.ToArray()));
}
// The output for the above input is:
// > Have duplicate a with indices 0,1,4
// > Have duplicate b with indices 3,5
Of course, the provided results must be used correctly - and this depends on what must ultimately be done.
You can select all the items, with their indexes, with:
tempList = targetFileList.Select((item, index) =>
new { Value = item, Index = index }).Where(x => x.Value == baselineFilename);
Now, you can create lists of the names and corresponding indexes with:
var indexes = tempList.Select(x => x.Index).ToList();
And the values:
currentTargetFiles = tempList.Select(x => x.Value).ToList();
Then, indexes[0] will hold the list index of currentTargetFiles[0].
int i = -1;
var currentTargetFiles = targetFileList.Select(x => new
{
Value = x,
Index = i++
})
.Where(x => x.Value == baselineFilename);
Is linq a requirement?
A traditional for loop and a dictionary would do fine:
Dictionary<int, string> currentTargetFiles = new Dictionary<int, string>();
for (int i = 0; i < targetFileList.Count; ++i)
if(targetFileList[i] == baselineFilename)
currentTargetFiles.Add(i, targetFileList[i]);
P.S.:
Just realized that you comparing an exact string (item == baselineFilename).
If this is the case you don't even need to keep each value for each index (since all values are the same).
List<int> currentTargetFilesIndices = new List<int>();
for (int i = 0; i < targetFileList.Count; ++i)
if(targetFileList[i] == baselineFilename)
currentTargetFiles.Add(i);
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())