I have the following json file:
[{"fruits": ["strawberry"]}, {"fruits": ["mango"]}, {"fruits": ["strawberry", "kiwi"]}]
I have the following class
class shake
{
public List<string> fruits = new List<string>();
}
I know this will give me all unique fruits:
var fruits = JsonConvert.DeserializeObject<List<shake>>(json);
var shakes = fruits
.GroupBy(t => t.fruits[0])
.Select(group => new
{
fruit = group.Key,
Count = group.Count()
})
.OrderByDescending(x => x.Count);
I'm trying to get a sorted list with the most popular fruits.
Is it possible to group by multiple elements and get the frequency? is possible to do it with linq?
I think in your example, you are missing the kiwi. I think what you are after is the SelectMany function in Linq.
public class Shake
{
public List<string> Fruits = new List<string>();
}
var list =
(
from shake in shakes
from fruit in shake.Fruits
group fruit by fruit into fruitGroup
let category = new { Fruit = fruitGroup.Key, Count = fruitGroup.Count() }
orderby category.Count descending
select category
).ToList();
I am not sure exactly what final result you are looking for. How close is this?
class Shake
{
public List<string> fruits = new List<string>();
}
static void Main(string[] args)
{
string json = "[{\"fruits\": [\"strawberry\"]}, {\"fruits\": [\"mango\"]}, {\"fruits\": [\"strawberry\", \"kiwi\"]}]";
List<Shake> fruitList = JsonConvert.DeserializeObject<List<Shake>>(json);
var shakes = fruitList.SelectMany(x => x.fruits)
.GroupBy(t => t)
.Select(group => new
{
fruit = group.Key,
Count = group.Count()
})
.OrderByDescending(x => x.Count).ToList();
Console.WriteLine(JsonConvert.SerializeObject(shakes));
}
The output is:
[{"fruit":"strawberry","Count":2},{"fruit":"mango","Count":1},{"fruit":"kiwi","Count":1}]
fruits.SelectMany(x=>x.fruits).GroupBy(x=>x).OrderByDescending(x=>x.Count()).ToDictionary(x=>x.Key, x=>x.Count())
here we on the output get the dictionary where key is name of fruit and value is the count
Related
I have a list:
public static List<PhraseSource> phraseSources;
The list has property:
public int? JishoJlpt { get; set; }
I am trying to get a count of the number of how many of each number of JishJlpt occur:
phraseSources.GroupBy(p => p.JishoJlpt)
.Select(g => new {
JishoJlpt g.Key,
Count: g.Count()
});
But it's giving me this error:
Can anyone help and give me advice on what might be wrong?
Looks like a syntax error. Anonymous objects use = instead of :
This works for me:
List<int> list = new List<int>();
list.Add(1);
list.Add(1);
list.Add(3);
var items = list.GroupBy(p => p)
.Select(g => new {
Key = g.Key,
Count = g.Count()
});
i'm new to linq and i've tried this function which should check for duplicates. what i want to do is to check through my list of buildingobjects to check if any buildingobject contains an objectID identical to another buildingObject in the list. finally i want to use the GUID of the buildingObject which had a duplicate, and print it to my log for the user to see.
public class FMBuildingObject
{
public Int64 ObjectId { get; set; }
public string GUID { get; set; }
}
the building object is bigger, but this is the values i'm using.
next i'm trying to use the buildingobjects, find duplicates and then print the GUID out. however i can't figure out how to access that GUID.
var query =
buildingObjects
.GroupBy(x => new { x })
.Select(group => new { Name = group.Key, Count = group.Count() })
.OrderByDescending(x => x.Count);
foreach (var q in query)
{
var updateLog = new LogServiceModel()
{
LogType = LogTypes.Warning, Parameters = { {?GUID?}}, LogTitle = "You have used two different classifications on a same Buildingobject in {0}. "
};
logService.Create(updateLog);
}
This will return a List<string> containing the GUID's of the objects which has duplicate ObjectId's:
var result = buildingObjects
.GroupBy(b => b.ObjectId)
.Where(g => g.Count() > 1)
.SelectMany(g => g.Select(b => b.GUID)).ToList();
You can get duplicate objects by:
var query = buildingObjects.GroupBy(x => new { x.ObjectId, x.GUID })
.Where(g => g.Count() > 1)
.Select(group => new { Name = group.Key, group.Key.GUID, group.Key.ObjectId }); //I don't know what is Name and why it's equal to Key
Then inside your foreach loop:
foreach (var q in query)
{
var updateLog = new LogServiceModel()
{
LogType = LogTypes.Warning, Parameters = q.GUID, LogTitle = $"You have used two different classifications on a same Buildingobject, Id: {q.ObjectId}. "
};
logService.Create(updateLog);
}
Or you can simply do:
var query = buildingObjects.GroupBy(x => new { x.ObjectId, x.GUID })
.Where(g => g.Count() > 1)
.Select(group => new LogServiceModel()
{
LogType = LogTypes.Warning,
Parameters = group.Key.GUID,
LogTitle = $"You have used two different classifications on a same Buildingobject, Id: {group.Key.ObjectId}."
});
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 am trying to Sort a List by it's names, but I don't know how to do it when i just have got a ID. Example:
public class CustomTask {
int categoryid;
}
public class DataOption {
int id;
string name;
}
public void Sort() {
List<DataOption> TheListContainingTheCategories = ...;
// The List containing my CustomTasks
List<CustomTask> listTempTasks = ...
var listTasksSorted = listTempTasks.OrderBy(...).ToList();
}
Sorting the IDs is not really hard, but how do i do that when i want to sort it by the names?
Thanks for your help
Guess the shortest way to do this is
var listTasksSorted = from ct in listTempTasks
join d in TheListContainingTheCategories on ct.categoryid equals d.id
orderby d.name
select new {ct, d};
then listTasksSorted looks like this
So The list is ordered by Name and the id's are together and no need of extra functions or members
An Alternative would be
var listTasksSortedAlternative = TheListContainingTheCategories.Where(d =>
listTempTasks.Any(ct =>
d.id == ct.categoryid)).OrderBy(d => d.name);
Which would look like
Try this:
public void Sort()
{
List<DataOption> TheListContainingTheCategories = ...;
Dictionary<int, string> lookup = TheListContainingTheCategories.ToDictionary(x => x.id, x => x.name);
List<CustomTask> listTempTasks = new List<CustomTask>();
var listTasksSorted = listTempTasks.OrderBy(c => lookup[c.categoryid]).ToList();
}
given that you want to sort by the matching
DataOption.name when DataOption.id == CustomTask.categoryId
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());