如何确定集合中出现次数最多的值
本文关键字:何确定 集合 | 更新日期: 2023-09-27 18:07:57
所以,我有一个json文件,其中有一个水果列表。水果键可以映射到单个水果或水果集合。
E。g:
[
{
"fruits": [
"banana"
]
},
{
"fruits": [
"apple"
]
},
{
"fruits": [
"orange",
"apple"
]
}
]
我想知道,我怎么能确定哪些水果(s)发生在我的json结构最多?也就是说,我如何知道一个值出现的频率以及哪个值领先于其他值?
不确定您是否对要反序列化到的类感兴趣,但是您可以这样做。可以随意跳过这个类,使用动态反序列化:
class FruitCollection
{
string[] Fruits { get; set; }
}
var fruitColls = JsonConvert.DeserializeObject<FruitCollection>(json);
var mostCommon = fruitColls
.SelectMany(fc => fc.Fruits)
.GroupBy(f => f)
.OrderByDescending(g => g.Count())
.First()
.Key;
编辑:
这个问题很老了,但是我要提到OrderByDescending
, First
是做冗余的工作:你真的不需要排序来得到最大值。这是一个古老的懒惰的黑客,人们一直在做,因为LINQ没有提供一个很好的MaxBy
扩展方法。
通常你的输入大小足够小,其他东西增加了足够的开销,你并不真正关心,但"正确"的方式(例如,如果你有数十亿种水果类型)将是使用适当的MaxBy扩展方法或从Aggregate
中破解一些东西。查找最大值是最坏情况线性的,而排序是最坏情况O(n log(n))
。
如果使用Json。. NET,您可以使用LINQ加载json,然后使用SelectTokens
递归地找到所有"fruits"
属性,然后递归地收集所有后代字符串值(JValue
类型的字符串值),按字符串值分组,并按降序排列:
var token = JToken.Parse(jsonString);
var fruits = token.SelectTokens("..fruits") // Recursively find all "fruit" properties
.SelectMany(f => f.DescendantsAndSelf()) // Recursively find all string literals undernearh each
.OfType<JValue>()
.GroupBy(f => (string)f) // Group by string value
.OrderByDescending(g => g.Count()) // Descending order by count.
.ToList();
或者,如果您希望将结果置于匿名类型中,则可以:
var fruits = token.SelectTokens("..fruits") // Recursively find all "fruit" properties
.SelectMany(f => f.DescendantsAndSelf()) // Recursively find all string literals undernearh each
.OfType<JValue>()
.GroupBy(f => (string)f) // Group by string value
.Select(g => new { Fruit = (string)g.Key, Count = g.Count() } )
.OrderByDescending(f => f.Count) // Descending order by count.
.ToList();
然后之后:
Console.WriteLine(JsonConvert.SerializeObject(fruits, Formatting.Indented));
生产:
[ { "Fruit": "apple", "Count": 2 }, { "Fruit": "banana", "Count": 1 }, { "Fruit": "orange", "Count": 1 } ]
** Update **
忘记包含以下扩展方法
public static class JsonExtensions
{
public static IEnumerable<JToken> DescendantsAndSelf(this JToken node)
{
if (node == null)
return Enumerable.Empty<JToken>();
var container = node as JContainer;
if (container != null)
return container.DescendantsAndSelf();
else
return new [] { node };
}
}
最初的问题在JSON的精确结构上有点模糊,这就是为什么我建议使用Linq而不是反序列化
这个结构的序列化类很简单:
public class RootObject
{
public List<List<string>> fruits { get; set; }
}
反序列化:
var fruitListContainer = JsonConvert.DeserializeObject<RootObject>(jsonString);
然后你可以把所有的水果放在一个列表里:
List<string> fruits = fruitListContainer.fruits.SelectMany(f => f);
现在你把所有的水果放在一个列表里,你可以做任何你想做的事情。
假设数据位于名为fruits的文件中。jq (http://stedolan.github.io/jq/)在PATH上,并且您正在使用Mac或linux风格的shell:
$ jq 'reduce (.[].fruits[]) as $fruit ({}; .[$fruit] += 1)' fruits.json
{
"banana": 1,
"apple": 2,
"orange": 1
}
在Windows上,如果适当地调整引号,同样的事情也会起作用。或者,如果将一行jq程序放在一个文件中,比如fruits。Jq,以下命令可以在任何受支持的环境中运行:
jq -f fruits.jq fruits.json
如果数据来自其他进程,您可以将其管道传输到jq,例如:
jq -f fruits.jq
找到最大计数的一种方法是添加一对过滤器,例如:
$ jq 'reduce (.[].fruits[]) as $fruit ({}; .[$fruit] += 1) |
to_entries | max_by(.value)' fruits.json
{
"key": "apple",
"value": 2
}