I have an array list. Which contains month number and data as comma separated.
Now I want to loop through this list and check if any month number is missing. If then need to add that month number in order with data part as zero.
List<string> MyData = new List<string>();
MyData.Add("4,500"); //dynamically adding. 4(april) and 6(june) are month numbers.
MyData.Add("6,400");
foreach (string str in MyData)
{
int GetmonthNum = Convert.ToInt32(str.Substring(0, str.IndexOf(',')));
}
Now need to add all other missing month number with value as zero. The resulted List should be
"4,500","5,0","6,400","7,0","8,0","9,0","10,0","11,0","12,0","1,0","2,0","3,0"
You could use contains like this
var result = new List<string>();
for (int i = 1; i <= 12 ; i++)
{
var firstMatch = myData.FirstOrDefault(x => x.Contains(i + ","));
if (firstMatch == null)
{
result.Add(i + ",0");
}
else
{
result.Add(firstMatch);
}
// or short code: result.Add(firstMatch ?? i + ",0" );
}
If you want "4,500" is the first item then try it
var minMonth = myData.Min(x => Convert.ToInt32(x.Substring(0, x.IndexOf(",", StringComparison.CurrentCulture))));
var result = new List<string>();
for (int i = minMonth - 1; i < minMonth + 11; i++)
{
var firstMatch = myData.FirstOrDefault(x => x.StartsWith((i % 12) + 1 + ","));
result.Add(firstMatch ?? (i % 12) + 1 + ",0");
}
In case if there are 12 item in your list [respective to 12 month] try below code
List<string> MyData = new List<string>();
MyData.Add("4,500"); //dynamically adding. 4(april) and 6(june) are month numbers.
MyData.Add("6,400");
int i = 1;
// use variable i from 1 to 12 as month indicator
foreach (string str in MyData)
{
string month = str.Substring(0, str.IndexOf(','));
// get the month from your list item here
int GetmonthNum = Convert.ToInt32( month==string.Empty || month==null ? i.ToString() : month );
// here use conditional operator to check if month is not there in list item , if it is not present than return i as misisng month
i++;
}
Let me know if you feel any problem in putting the code together
List<string> MyData = new List<string>();
MyData.Add("4,500");
MyData.Add("6,400");
var months = Enumerable.Range(1, 12);
foreach (int month in months)
{
if (MyData.Any(a => a.Split(',')[0] == month.ToString()))
continue;
MyData.Add(string.Format("{0},{1}", month.ToString(), "0"));
}
This works:
MyData =
MyData
.Select(x => x.Split(',').Select(y => int.Parse(y)).ToArray())
.Concat(Enumerable.Range(1, 12).Select(x => new [] { x, 0 }).ToArray())
.OrderBy(x => x[0])
.GroupBy(x => x[0], x => x[1])
.SelectMany(x => x.Take(1), (y, z) => $"{y.Key},{z}")
.ToList();
And that gives:
1,0
2,0
3,0
4,500
5,0
6,400
7,0
8,0
9,0
10,0
11,0
12,0
I was able to achieve your desired result with the following loop. There are many ways to do it though.
int arrayIndex = 0;
int month = 1;
for (int i = 0; i < 12; i++)
{
if (myArray[arrayIndex].Split(',')[0] == Convert.ToString(month))
{
MyData.Add(myArray[arrayIndex]);
month++;
arrayIndex++;
}
else
{
MyData.Add(Convert.ToString(month) + ",0");
month++;
}
}
Related
Given 2 datasets (which are both a sequence of standard deviations away from a number, we are looking for the overlapping sections):
var list1 = new decimal[] { 357.06, 366.88, 376.70, 386.52, 406.15 };
var list2 = new decimal[] { 370.51, 375.62, 380.72, 385.82, 390.93 };
I would like to perform a merge with items from List2 being placed closest to items of List1, within a certain range, i.e. merge List2 element within 5.10 (standard deviation) of List1 element:
357.06
366.88 => 370.51
376.70 => 375.52, 380.72
386.52 => 390.93
406.15
The idea is to cluster values from List2 and count them, in this case element with value 376.70 would have the highest significance as it has 2 close neighbors of 375.52 and 380.72 (where as 366.88 and 386.52 have only 1 match, and the remaining none within range).
Which C# math/stats libraries could be used for this (or would there be a better way to combine statistically)?
If this is more of a computer science or stats question apologies in advance will close and reopen on relevant SO site.
Assuming that list2 is sorted (if not, put Array.Sort(list2);) you can try Binary Search:
Given:
var list1 = new decimal[] { 357.06m, 366.88m, 376.70m, 386.52m, 406.15m };
var list2 = new decimal[] { 370.51m, 375.62m, 380.72m, 385.82m, 390.93m };
decimal sd = 5.10m;
Code:
// Array.Sort(list2); // Uncomment, if list2 is not sorted
List<(decimal value, decimal[] list)> result = new List<(decimal value, decimal[] list)>();
foreach (decimal value in list1) {
int leftIndex = Array.BinarySearch<decimal>(list2, value - sd);
if (leftIndex < 0)
leftIndex = -leftIndex - 1;
else // edge case
for (; leftIndex >= 1 && list1[leftIndex - 1] == value - sd; --leftIndex) ;
int rightIndex = Array.BinarySearch<decimal>(list2, value + sd);
if (rightIndex < 0)
rightIndex = -rightIndex - 1;
else // edge case
for (; rightIndex < list1.Length - 1 && list1[rightIndex + 1] == value + sd; ++rightIndex) ;
result.Add((value, list2.Skip(leftIndex).Take(rightIndex - leftIndex).ToArray()));
}
Let's have a look:
string report = string.Join(Environment.NewLine, result
.Select(item => $"{item.value} => [{string.Join(", ", item.list)}]"));
Console.Write(report);
Outcome:
357.06 => []
366.88 => [370.51]
376.70 => [375.62, 380.72]
386.52 => [385.82, 390.93]
406.15 => []
Something like this should work
var list1 = new double[] { 357.06, 366.88, 376.70, 386.52, 406.15 };
var list2 = new double[] { 370.51, 375.62, 380.72, 385.82, 390.93 };
double dev = 5.1;
var result = new Dictionary<double, List<double>>();
foreach (var l in list2) {
var diffs = list1.Select(r => new { diff = Math.Abs(r - l), r })
.Where(d => d.diff <= dev)
.MinBy(r => r.diff)
.FirstOrDefault();
if (diffs == null) {
continue;
}
List<double> list;
if (! result.TryGetValue(diffs.r, out list)) {
list = new List<double>();
result.Add(diffs.r, list);
}
list.Add(l);
}
It uses MinBy from MoreLinq, but it is easy to modify to work without it.
In fact, you don't need extra libs or something else. You can use just LINQ for this.
internal class Program
{
private static void Main(string[] args)
{
var deviation = 5.1M;
var list1 = new decimal[] { 357.06M, 366.88M, 376.70M, 386.52M, 406.15M };
var list2 = new decimal[] { 370.51M, 375.62M, 380.72M, 385.82M, 390.93M };
var result = GetDistribution(list1.ToList(), list2.ToList(), deviation);
result.ForEach(x => Console.WriteLine($"{x.BaseValue} => {string.Join(", ", x.Destribution)} [{x.Weight}]"));
Console.ReadLine();
}
private static List<Distribution> GetDistribution(List<decimal> baseList, List<decimal> distrebutedList, decimal deviation)
{
return baseList.Select(x =>
new Distribution
{
BaseValue = x,
Destribution = distrebutedList.Where(y => x - deviation < y && y < x + deviation).ToList()
}).ToList();
}
}
internal class Distribution
{
public decimal BaseValue { get; set; }
public List<decimal> Destribution { get; set; }
public int Weight => Destribution.Count;
}
I hope it was useful for you.
I want to remove the repeating items of a list.I can realize it whit Distinct() easily.But i also need to get the order number of the items which have been removed.I can't find any function in linq to solve the problem and finally realize it with the following code:
public List<string> Repeat(List<string> str)
{
var Dlist = str.Distinct();
List<string> repeat = new List<string>();
foreach (string aa in Dlist)
{
int num = 0;
string re = "";
for (int i = 1; i <= str.LongCount(); i++)
{
if (aa == str[i - 1])
{
num = num + 1;
re = re + " - " + i;
}
}
if (num > 1)
{
repeat.Add(re.Substring(3));
}
}
return repeat;
}
Is there any other way to solve the problem more simple? Or is there any function in linq I missed?Any advice will be appreciated.
This query does exactly the same as your function, if I'm not mistaken:
var repeated = str.GroupBy(s => s).Where(group => group.Any())
.Select(group =>
{
var indices = Enumerable.Range(1, str.Count).Where(i => str[i-1] == group.Key).ToList();
return string.Join(" - ", group.Select((s, i) => indices[i]));
});
It firstly groups the items of the original list, so that every item with the same content is in a group. Then it searches for all indices of the items in the group in the original list, so that we have all the indices of the original items of the group. Then it joins the indices to a string, so that the resulting format is similiar to the one you requested. You could also transform this statement lambda to an anonymous lambda:
var repeated = str.GroupBy(s => s).Where(group => group.Any())
.Select(group => string.Join(" - ",
group.Select((s, i) =>
Enumerable.Range(1, str.Count).Where(i2 => str[i2 - 1] == group.Key).ToList()[i])));
However, this significantly reduces performance.
I tested this with the following code:
public static void Main()
{
var str = new List<string>
{
"bla",
"bla",
"baum",
"baum",
"nudel",
"baum",
};
var copy = new List<string>(str);
var repeated = str.GroupBy(s => s).Where(group => group.Any())
.Select(group => string.Join(" - ",
group.Select((s, i) =>
Enumerable.Range(1, str.Count).Where(i2 => str[i2 - 1] == group.Key).ToList()[i])));
var repeated2 = Repeat(str);
var repeated3 = str.GroupBy(s => s).Where(group => group.Any())
.Select(group =>
{
var indices = Enumerable.Range(1, str.Count).Where(i => str[i-1] == group.Key).ToList();
return string.Join(" - ", group.Select((s, i) => indices[i]));
});
Console.WriteLine(string.Join("\n", repeated) + "\n");
Console.WriteLine(string.Join("\n", repeated2) + "\n");
Console.WriteLine(string.Join("\n", repeated3));
Console.ReadLine();
}
public static List<string> Repeat(List<string> str)
{
var distinctItems = str.Distinct();
var repeat = new List<string>();
foreach (var item in distinctItems)
{
var added = false;
var reItem = "";
for (var index = 0; index < str.LongCount(); index++)
{
if (item != str[index])
continue;
added = true;
reItem += " - " + (index + 1);
}
if (added)
repeat.Add(reItem.Substring(3));
}
return repeat;
}
Which has the followin output:
1 - 2
3 - 4 - 6
5
1 - 2
3 - 4 - 6
5
1 - 2
3 - 4 - 6
5
Inside your repeat method you can use following way to get repeated items
var repeated = str.GroupBy(s=>s)
.Where(grp=>grp.Count()>1)
.Select(y=>y.Key)
.ToList();
I'm querying a datatable and I seem stuck on selecting a group of groups.
This code
var grouping = table.AsEnumerable()
.Where(x => curveids.Contains(x.Field<short>("CurveID")) && x.Field<DateTime>("Timestamp").Hour >= hour && x.Field<DateTime>("Timestamp").Hour < (hour + 1))
.GroupBy(x => x.Field<DateTime>("Timestamp")).Where(x => x.Select(y => y["CurveID"]).Count() == curveids.Count);
Groups by timestamp and returns a group of x curves, where x = curveid.Count(). It contains 5000ish groups.
However for each day there can be more than one timestamp.
int nrdays = grouping.GroupBy(z => z.Key.Date).Count();
tells me there are 255 distinct days.
I would now like to group this again, but not by time stamp but by calendar day and then take the first (as in earliest) group for each day. I tried this:
var grouping2 = grouping.GroupBy(z => z.Key.Date).OrderBy(a => a.Key).Take(curveids.Count);
but this only returns 4 groups and I dont get why?
It should return 255 groups with each of them containing the same timestamp and x curveids, so x*255 record sets.
The datatable has 3 columns, Timestamp (DateTime), CurveID(short), Price(double).
UPDATE
As requested by Mr Skeet a full example:
public class listprx
{
public DateTime timestamp;
public int curveID;
public double prx;
}
static void Main(string[] args)
{
var data = new List<listprx>();
// populating data
for (int i = 0; i < 50000; i++)
{
Random rand = new Random(i);
var tempdt = new DateTime(2016, rand.Next(1, 12), rand.Next(1, 29), rand.Next(1, 23), rand.Next(1, 59), 0);
if(i % 3 == 0)
{
data.Add(new listprx { timestamp = tempdt, curveID = 1, prx = rand.Next(1,50)});
data.Add(new listprx { timestamp = tempdt, curveID = 2, prx = rand.Next(1, 50) });
}
else if (i % 5 == 0)
{
data.Add(new listprx { timestamp = tempdt, curveID = 1, prx = rand.Next(1, 50) });
}
else
{
data.Add(new listprx { timestamp = tempdt, curveID = 1, prx = rand.Next(1, 50) });
data.Add(new listprx { timestamp = tempdt, curveID = 2, prx = rand.Next(1, 50) });
data.Add(new listprx { timestamp = tempdt, curveID = 3, prx = rand.Next(1, 50) });
}
}
// setting hour criteria
int hour = 16;
int nrcurves = 3;
// grouping by timestamp and only take those where all curves are there, (as close to the desired time as possible
var grouping = data.Where(x => x.timestamp.Hour >= hour && x.timestamp.Hour < (hour + 1))
.GroupBy(x => x.timestamp).Where(x => x.Select(y => y.curveID).Count() == nrcurves);
// Grouping by day and take only the time stamp that is closest to the hour
// this fails
var grouping2 = grouping.GroupBy(z => z.Key.Date).OrderBy(a => a.Key).Take(nrcurves);
Console.WriteLine("Nr of timestamps with all curves {0}, nr of days {1}, nr of groups in second group {2}, expected same as nr days"
, grouping.Count(), grouping.GroupBy(z => z.Key.Date).Count(), grouping2.Count());
Console.ReadLine();
}
UPDATE 2
I have removed the random element and simplified further:
public class listprx
{
public DateTime timestamp;
public int curveID;
}
static void Main(string[] args)
{
var data = new List<listprx>();
// populating data
var tempdt = new DateTime(2016, 4, 6, 16, 1, 0);
for (int i = 0; i < 4; i++)
{
if (i == 2)
{
tempdt = tempdt.AddDays(1);
}
if(i % 2 == 0 )
{
data.Add(new listprx { timestamp = tempdt, curveID = 1});
}
else
{
data.Add(new listprx { timestamp = tempdt, curveID = 1});
data.Add(new listprx { timestamp = tempdt, curveID = 2});
}
tempdt = tempdt.AddMinutes(i+1);
}
// setting hour criteria
int hour = 16;
int nrcurves = 2;
//grouping by timestamp and only take those where all curves are there, (as close to the desired time as possible
var grouping = data.Where(x => x.timestamp.Hour >= hour && x.timestamp.Hour < (hour + 1))
.GroupBy(x => x.timestamp).Where(x => x.Select(y => y.curveID).Count() == nrcurves);
//Grouping by day and take only the time stamp that is closest to the hour
//this fails
var grouping2 = grouping.GroupBy(z => z.Key.Date).OrderBy(a => a.Key).Take(nrcurves);
Console.WriteLine("Nr of timestamps with all curves {0}, nr of days {1}, nr of groups in second group {2}, expected same as nr days"
, grouping.Count(), grouping.GroupBy(z => z.Key.Date).Count(), grouping2.Count());
Console.ReadLine();
}
The expected end result is:
Timestamp CurveID
------------------------
6/4/16 16:02 1
6/4/16 16:02 2
7/4/16 16:06 1
7/4/16 16:06 2
Edited answer working on your example.
Ok, I went trought your example and fixed some bugs and my answer. Let's clear code a bit and comment what went wrong where.
Our models will be
public class Curve
{
public int CurveID { get; set; }
public DateTime Timestamp { get; set; }
}
public class CurveGroup
{
public DateTime Timestamp { get; set; }
public IEnumerable<Curve> Curves { get; set; }
}
next is function to generate test data:
public static List<Curve> GetData()
{
var data = new List<Curve>();
var startTime = new DateTime(2016, 4, 6, 16, 1, 0);
for (int i = 0; i < 4; i++)
{
if (i == 2)
{
//startTime.AddDays(1); - this line does nothing, DateTime is an immutable struct so all function changing its value returns a new copy
startTime = startTime.AddDays(1);
}
if (i % 2 == 0)
{
data.Add(CreateNewCurve(startTime, 1));
}
else
{
data.Add(CreateNewCurve(startTime, 1));
data.Add(CreateNewCurve(startTime, 2));
}
//startTime.AddMinutes(i + 1); same issue as above
startTime = startTime.AddMinutes(i + 1);
}
return data;
}
public static Curve CreateNewCurve(DateTime time, int curveID)
{
return new Curve()
{
Timestamp = time,
CurveID = curveID
};
}
and here goes main function
static void Main(string[] args)
{
var data = GetData();
int hour = 16;
int totalCurveCount = 2;
var grouping = data
.Where(x => x.Timestamp.Hour >= hour && x.Timestamp.Hour < (hour + 1))
.GroupBy(x => x.Timestamp)
.Where(x => x.Count() == totalCurveCount); //there is no need to select curveId like in your code: Where(x => x.Select(y => y.curveID).Count() == nrcurves);
var grouping2 = grouping
.GroupBy(x => x.Key.Date)
.Select(x =>
new CurveGroup
{
Timestamp = x.Key,
Curves = x.OrderBy(c => c.Key).Take(totalCurveCount).SelectMany(c => c)
}
);
foreach (var g in grouping2)
{
foreach (var c in g.Curves)
{
Console.WriteLine(c.Timestamp);
Console.WriteLine(c.CurveID);
}
}
}
this returns expected results.
Your code failed because your second grouping is not taking (Take(nrcurves)) values in groups but groups themselves. So instead of returning 255 groups with 2 values in each you return 2 groups with all values in them.
Hope this fixes your issue.
I have two arrays and i am trying to get all possible sum of each element with other element of two array and index of each element
int[] width = new int[2] {10,20 };
int[] height = new int[2] {30,40 };
result should like this (value / indexes)
10 width0
10+20 width0+width1
10+30 width0+height0
10+40 width0+height1
10+20+30 width0+width1+height0
10+20+40 width0+width1+height1
10+20+30+40 width0+width1+height0+height1
And so for each element in two array
I tried using permutation but I get other output
It is more easy to get all combinations from one array than two arrays. And as we see, you need to store indices and array names along with the value of the elements in collections. So, in my opinion the best option is to combine these two arrays in one dictionary, where the key will be the value of the numbers and the value will be [ArrayName + Index of item] (f.e width0, height1 and so on....)
So, let's combine these arrays in one dictionary:
int[] width = new int[2] { 10, 20 };
int[] height = new int[2] { 30, 40 };
var widthDictionary = width.ToList().Select((number, index) => new { index, number })
.ToDictionary(key => key.number, value => string.Format("width{0}", value.index));
var heightDictionary = height.ToList().Select((number, index) => new { index, number })
.ToDictionary(key => key.number, value => string.Format("height{0}", value.index));
// And here is the final dictionary
var totalDictionary = widthDictionary.Union(heightDictionary);
Then add this method to your class: (source)
public static IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
Then send your dictionary as an argument to this method and project this collection as you want with the help of the Select() method:
var sumOfCombinations = GetPowerSet(totalDictionary.ToList())
.Where(x => x.Count() > 0)
.Select(x => new
{
Numbers = x.Select(pair => pair.Key).ToList(),
DisplayValues = x.Select(pair => pair.Value).ToList()
})
.ToList();
And at the end you can display expected result as this:
sumOfCombinations.ForEach(x =>
{
x.Numbers.ForEach(number => Console.Write("{0} ", number));
x.DisplayValues.ForEach(displayValue => Console.Write("{0} ", displayValue));
Console.WriteLine();
});
And, the result is:
This is a play off of #Farhad Jabiyev's answer.
Declares a class called IndexValuePair. and uses foreach on widthList and heightList. to populate the 'Index' property of item instance.
Note: Index is a string.
Class & Static Function
public class IndexValuePair
{
public string Index {get;set;}
public int Value {get;set;}
}
public static IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
Main (Console)
static void Main(string[] args)
{
int[] width = new int[2] { 10, 20 };
int[] height = new int[2] { 30, 40 };
var wholeList = width.Select(val => new IndexValuePair() { Index = "width", Value = val }).ToList();
var heightList = height.Select(val => new IndexValuePair() { Index = "height", Value = val }).ToList();
var iteration = 0;
wholeList.ForEach(ivp => { ivp.Index = ivp.Index + count; count = iteration + 1; });
iteration = 0;
heightList.ForEach(ipv => { ivp.Index = ivp.Index + count; count = iteration + 1; });
wholeList.AddRange(heightList);
var sumOfCombinations = GetPowerSet(wholeList).Where(x => x.Count() > 0)
.Select(x => new { Combination = x.ToList(), Sum = x.Sum(ivp => ivp.Value) }).ToList();
StringBuilder sb = new StringBuilder();
sumOfCombinations.ForEach(ivp =>
{
ivp.Combination.ForEach(pair => sb.Append(string.Format("{0} ", pair.Value)));
sb.Append(string.Format("= {0} = ", x.Sum));
ivp.Combination.ForEach(pair=> sb.Append(string.Format("{0} + ", pair.Index)));
sb.Length -= 3;
Console.WriteLine(sb);
sb.Clear();
});
var key = Console.ReadKey();
}
This question already has answers here:
C# LINQ find duplicates in List
(13 answers)
Closed 3 years ago.
I have a List<string> which has some words duplicated. I need to find all words which are duplicates.
Any trick to get them all?
In .NET framework 3.5 and above you can use Enumerable.GroupBy which returns an enumerable of enumerables of duplicate keys, and then filter out any of the enumerables that have a Count of <=1, then select their keys to get back down to a single enumerable:
var duplicateKeys = list.GroupBy(x => x)
.Where(group => group.Count() > 1)
.Select(group => group.Key);
If you are using LINQ, you can use the following query:
var duplicateItems = from x in list
group x by x into grouped
where grouped.Count() > 1
select grouped.Key;
or, if you prefer it without the syntactic sugar:
var duplicateItems = list.GroupBy(x => x).Where(x => x.Count() > 1).Select(x => x.Key);
This groups all elements that are the same, and then filters to only those groups with more than one element. Finally it selects just the key from those groups as you don't need the count.
If you're prefer not to use LINQ, you can use this extension method:
public void SomeMethod {
var duplicateItems = list.GetDuplicates();
…
}
public static IEnumerable<T> GetDuplicates<T>(this IEnumerable<T> source) {
HashSet<T> itemsSeen = new HashSet<T>();
HashSet<T> itemsYielded = new HashSet<T>();
foreach (T item in source) {
if (!itemsSeen.Add(item)) {
if (itemsYielded.Add(item)) {
yield return item;
}
}
}
}
This keeps track of items it has seen and yielded. If it hasn't seen an item before, it adds it to the list of seen items, otherwise it ignores it. If it hasn't yielded an item before, it yields it, otherwise it ignores it.
and without the LINQ:
string[] ss = {"1","1","1"};
var myList = new List<string>();
var duplicates = new List<string>();
foreach (var s in ss)
{
if (!myList.Contains(s))
myList.Add(s);
else
duplicates.Add(s);
}
// show list without duplicates
foreach (var s in myList)
Console.WriteLine(s);
// show duplicates list
foreach (var s in duplicates)
Console.WriteLine(s);
If you're looking for a more generic method:
public static List<U> FindDuplicates<T, U>(this List<T> list, Func<T, U> keySelector)
{
return list.GroupBy(keySelector)
.Where(group => group.Count() > 1)
.Select(group => group.Key).ToList();
}
EDIT: Here's an example:
public class Person {
public string Name {get;set;}
public int Age {get;set;}
}
List<Person> list = new List<Person>() { new Person() { Name = "John", Age = 22 }, new Person() { Name = "John", Age = 30 }, new Person() { Name = "Jack", Age = 30 } };
var duplicateNames = list.FindDuplicates(p => p.Name);
var duplicateAges = list.FindDuplicates(p => p.Age);
foreach(var dupName in duplicateNames) {
Console.WriteLine(dupName); // Will print out John
}
foreach(var dupAge in duplicateAges) {
Console.WriteLine(dupAge); // Will print out 30
}
Using LINQ, ofcourse.
The below code would give you dictionary of item as string, and the count of each item in your sourc list.
var item2ItemCount = list.GroupBy(item => item).ToDictionary(x=>x.Key,x=>x.Count());
For what it's worth, here is my way:
List<string> list = new List<string>(new string[] { "cat", "Dog", "parrot", "dog", "parrot", "goat", "parrot", "horse", "goat" });
Dictionary<string, int> wordCount = new Dictionary<string, int>();
//count them all:
list.ForEach(word =>
{
string key = word.ToLower();
if (!wordCount.ContainsKey(key))
wordCount.Add(key, 0);
wordCount[key]++;
});
//remove words appearing only once:
wordCount.Keys.ToList().FindAll(word => wordCount[word] == 1).ForEach(key => wordCount.Remove(key));
Console.WriteLine(string.Format("Found {0} duplicates in the list:", wordCount.Count));
wordCount.Keys.ToList().ForEach(key => Console.WriteLine(string.Format("{0} appears {1} times", key, wordCount[key])));
I'm assuming each string in your list contains several words, let me know if that's incorrect.
List<string> list = File.RealAllLines("foobar.txt").ToList();
var words = from line in list
from word in line.Split(new[] { ' ', ';', ',', '.', ':', '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
select word;
var duplicateWords = from w in words
group w by w.ToLower() into g
where g.Count() > 1
select new
{
Word = g.Key,
Count = g.Count()
}
I use a method like that to check duplicated entrys in a string:
public static IEnumerable<string> CheckForDuplicated(IEnumerable<string> listString)
{
List<string> duplicateKeys = new List<string>();
List<string> notDuplicateKeys = new List<string>();
foreach (var text in listString)
{
if (notDuplicateKeys.Contains(text))
{
duplicateKeys.Add(text);
}
else
{
notDuplicateKeys.Add(text);
}
}
return duplicateKeys;
}
Maybe it's not the most shorted or elegant way, but I think that is very readable.
lblrepeated.Text = "";
string value = txtInput.Text;
char[] arr = value.ToCharArray();
char[] crr=new char[1];
int count1 = 0;
for (int i = 0; i < arr.Length; i++)
{
int count = 0;
char letter=arr[i];
for (int j = 0; j < arr.Length; j++)
{
char letter3 = arr[j];
if (letter == letter3)
{
count++;
}
}
if (count1 < count)
{
Array.Resize<char>(ref crr,0);
int count2 = 0;
for(int l = 0;l < crr.Length;l++)
{
if (crr[l] == letter)
count2++;
}
if (count2 == 0)
{
Array.Resize<char>(ref crr, crr.Length + 1);
crr[crr.Length-1] = letter;
}
count1 = count;
}
else if (count1 == count)
{
int count2 = 0;
for (int l = 0; l < crr.Length; l++)
{
if (crr[l] == letter)
count2++;
}
if (count2 == 0)
{
Array.Resize<char>(ref crr, crr.Length + 1);
crr[crr.Length - 1] = letter;
}
count1 = count;
}
}
for (int k = 0; k < crr.Length; k++)
lblrepeated.Text = lblrepeated.Text + crr[k] + count1.ToString();