I have a list of string items declared like this:
List<string> methodList = new List<string>();
I do what I need to get done and the results are something like this:
Method1;15
Method2;30
Method3;45
Method1;60
I need to loop through this list and display a distinct list and the addition of the totals. Something like this:
Method1 75
Method2 30
Method3 45
In order to do this, you'll need to split this up, then sum:
var results = methodList
.Select(l => l.Split(';'))
.GroupBy(a => a[0])
.Select(g =>
new
{
Group = g.Key,
Count = g.Count(),
Total = g.Sum(arr => Int32.Parse(arr[1]))
});
foreach(var result in results)
Console.WriteLine("{0} {1} {2}", result.Group, result.Count, result.Total);
Something like this would work:
var sumList = methodList.Select( x=>
{
var parts = x.Split(';');
return new
{
Method = parts [0],
Cost = Convert.ToInt32(parts[1])
};
})
.GroupBy( x=> x.Method)
.Select( g=> new { Method = g.Key, Sum = g.Sum( x=> x.Cost) })
.ToList();
foreach(var item in sumList)
Console.WriteLine("Total for {0}:{1}", item.Method, item.Sum);
A better approach would be to keep the individual methods and their cost in a strongly typed class, so you don't have to do string parsing to operate them:
public class MethodCost
{
public string MethodName { get; set; }
public int Cost { get; set; }
}
Now you can use a List<MethodCost> instead and have direct access to the cost - use strings for presentation (i.e. writing to the console), not for internal storage when it is not appropriate.
Try the following
var result = methodList
.Select(
x =>
{
var items = x.Split(';');
return new { Name = items[0], Value = Int32.Parse(items[1]) };
})
.GroupBy(pair => pair.Name)
.Select(
grouping =>
{
var sum = grouping.Sum(x => x.Value);
return String.Format("{0} {1}", grouping.Key, sum);
});
Yet another, slightly compacter variant is
var results = from item in methodList
let parts = item.Split(';')
group Int32.Parse(parts[1]) by parts[0];
foreach(var item in results)
Console.WriteLine("{0} {1}", item.Key, item.Sum());
Related
I want to to display two tables information at a time.
List<int> order_track = db.Order_Trackings.Where(e => e.UID == id).Select(q => q.ID).ToList();
if (order_track == null)
{
var rate = db.Ratings.OrderByDescending(e => e.Rate).Take(5);
}
List<int> fidList = db.OrderFoods.Where(q => order_track.Contains(q.OID)).Select(q => q.FID).ToList();
var qs = (from x in fidList
group x by x into g
let count = g.Count()
orderby count descending
select new { KEY = g.Key });
if (order_track.Count == 2)
{
var one = qs;
List<int> idList = new List<int>();
foreach (var val in one)
{
idList.Add(val.KEY);
}
var food = db.Foods.Where(q => idList.Contains(q.ID));
var rate = db.Ratings.OrderByDescending(e => e.Rate).FirstorDefault();
return Request.CreateResponse(HttpStatusCode.OK, rate);
I want to do something like this I hope you will understand what i am trying to achieve Thanks in advance.
var food = db.Foods.Where(q => idList.Contains(q.ID)&&db.Ratings.OrderByDescending(e => e.Rate).FirstorDefault());
return Request.CreateResponse(HttpStatusCode.OK, rate);
If you want to combine the two results into one variable, then the easiest way to do so is by creating an anonymous object, like this:
var result = new
{
food = db.Foods.Where(q => idList.Contains(q.ID)),
rate = db.Ratings.OrderByDescending(e => e.Rate).FirstorDefault()
};
return Request.CreateResponse(HttpStatusCode.OK, result);
You could also create a class with two properties and then create an instance of that class, but if this is the only place where you would use that class then I wouldn't bother doing that.
I have a line of json that I deserialize and create a list of lists:
var json = #"[{'names': ['a','b']} ,{'names': ['z','y','j']} ,{'names':
['a','b']}]";
var json_converted = JsonConvert.DeserializeObject<List<RootObject>>(json);
var namelist = json_converted
I want to use linq to compare the list contents and see if the items in the list match another list
ex)
names............matching list count
List {a,b} = 2
List {z,y,j} = 1
I've tried the following, but no dice :/
var namelist = json_converted
.GroupBy(n => n.names)
.Select(i => new { name = i.Key, Count = i.Count() });
Any suggestions?
You can group by a string produced from your list items taken in the same order. Assuming that '|' character is not allowed inside names, you can do this:
var namelist = json_converted
.GroupBy(n => string.Join("|", n.names.OrderBy(s => s)))
.Select(g => new {
Name = g.First().names
, Count = g.Count()
});
This approach constructs a string "a|b" from lists ["a", "b"] and ["b", "a"], and use that string for grouping the content.
Since the keys are composed of ordered names, g.First().names used as Name may not be in the same order for all elements of the group.
You can write a comparer for the list of names.
public class NamesComparer : IEqualityComparer<IEnumerable<string>>
{
public bool Equals(IEnumerable<string> x, IEnumerable<string> y)
{
//do your null checks
return x.SequenceEqual(y);
}
public int GetHashCode(IEnumerable<string> obj)
{
return 0;
}
}
Then use that in GroupBy:
var namelist = json_converted.GroupBy(n => n.names, new NamesComparer())
.Select(i => new { name = i.Key, Count = i.Count() });
I have the following query where I use SelectMany on a list of lists and then GroupBy 'Name' and the 'Count' of the Lists and store the values in 'Name' and 'Count'.
var groups = originalList.SelectMany(fullList => fullList.ListOfItems, (fullList, details) => new { fullList.Name, fullList.ListOfItems })
.GroupBy(x => x.Name,
x => x.ListOfItems.Count())
.Select(g => new { Name = g.Key, Count = g.Count()});
//Do something with results
foreach (var item in groups)
{
var name = item.Name;
var count = item.Count;
}
Now there is another paramater from the originalList that I want to pass through to the resulting groups lets call it fullList.SomeOtherValue.
How can I modify this above so that it is passed through also?
I want to end up withthis:
foreach (var item in groups)
{
var name = item.Name;
var count = item.Count;
var someother = item.SomeOtherValue; <-- I want this as well
}
it sounds like something like this should work:
originalList.SelectMany(fullList => fullList.ListOfItems)
.GroupBy(x => new { x.Name, x.SomeOtherValue})
.Select(g => new { g.Key.Name, g.Key.SomeOtherValue, Count = g.Count()});
I have a list of model class with some fields in it,I want to apply group by and count on the base of ID on it,in my lst I have data like this
lst[0]=Id=10,Name="user1",Gender="Male",Course="course1";
lst[1]=Id=10,Name="user1",Gender="Male",Course="course2";
lst[2]=Id=10,Name="user1",Gender="Male",Course="course3";
lst[3]=Id=11,Name="user2",Gender="Male",Course="course4";
I want to count the course with group by on Id.
This is how I am doing
var result = lst.GroupBy(n => n.Id).Select(c => new { Key = c.Key, total = c.Count()});
But after applying this I am not getting any value in result variable(ie result.Name or result[0].Name)
How can I apply group by and count in this list so I get the list data after applying the group by too.
Having used GroupBy you have projected (Select(..)) to an anonymous object which throws away the selected items in the group; your result will be an IEnumerable<anonymous> of items with properties Key and total
var result = lst.GroupBy(n => n.Id)
.Select(c => new { Key = c.Key, total = c.Count()});
If you want to keep the selected items, you need to include this in your projection
var result = lst.GroupBy(n => n.Id)
.Select(c => new { Key = c.Key, total = c.Count(), Items = c});
foreach(var r in result)
{
Console.WriteLine("Key: {0} Count:{1}",r.Key,r.total)
foreach(var i in r.Items)
Console.WriteLine(i.Name);
}
The reason is because you are grouping by Id and just provinding an anonymous object with Key (which is the Id) and a Count. If you want to read the values, each item of the result group set will have the Count and the values where you can loop between them. For sample:
var result = lst.GroupBy(n => n.Id);
foreach (var g in result)
{
Console.WriteLine("For group {0} the total is {1}.", g.Key, g.Count());
foreach(var item in g)
{
Console.WriteLine("Name: {0}", item.Name);
}
}
All you have to do is call ToList or ToArray.
var result = lst.GroupBy(n => n.Id)
.Select(c => new
{
Key = c.Key,
total = c.Count(),
Gender = c.First().Gender
}).ToList();
Or alternativly - to avoid multiple iterations of the same enumeration:
var result = lst.GroupBy(n => n.Id)
.Select(c =>
{
var firstEl = c.First();
return new {
Key = c.Key,
total = c.Count(),
Gender = firstEl.Gender,
Name = firstEl.Name,
Course = firstEl.Course
}
}).ToList();
Select will only return a query which is deferredly executed. This means you get the result when you actually iterate on the enumeration, which is enforeced by calling one of the mentioned methods.
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.