【问题标题】:Sort by most occurring string from json by key order and order contains array itself按键顺序从json中最出现的字符串排序,顺序包含数组本身
【发布时间】:2019-06-17 20:18:44
【问题描述】:

我有 JSON 文件,其中包含与

相同的键作为数组的订单
[
   {
      "order":["Order1"]
   },
   {
      "order":["Order2"]
   },
   {
      "order":["Order2","Order3"]
   },
   {
      "order":["Order1","Order2"]
   },
   {
      "order":["Order2","Order3"]
   }
]

我希望它按出现次数最多的订单组合进行排序。

请帮帮我。

注意:这不是一个简单的字符串数组,请在将其标记为可能重复之前查看 json。

【问题讨论】:

标签: c# json asp.net-mvc entity-framework linq


【解决方案1】:

这可以按如下方式完成。首先,为您的订单引入一个数据模型,如下所示:

public class Order 
{
    public string[] order { get; set; }
}

接下来,为枚举定义以下相等比较器:

public class IEnumerableComparer<TEnumerable, TElement> : IEqualityComparer<TEnumerable> where TEnumerable : IEnumerable<TElement>
{
    //Adapted from IEqualityComparer for SequenceEqual
    //https://stackoverflow.com/questions/14675720/iequalitycomparer-for-sequenceequal
    //Answer https://stackoverflow.com/a/14675741 By Cédric Bignon https://stackoverflow.com/users/1284526/c%C3%A9dric-bignon 
    public bool Equals(TEnumerable x, TEnumerable y)
    {
        return Object.ReferenceEquals(x, y) || (x != null && y != null && x.SequenceEqual(y));
    }

    public int GetHashCode(TEnumerable obj)
    {
        // Will not throw an OverflowException
        unchecked
        {
            return obj.Where(e => e != null).Select(e => e.GetHashCode()).Aggregate(17, (a, b) => 23 * a + b);
        }
    }
}

现在您可以反序列化包含上面列出的订单的 JSON,并按如下所示的频率降序对唯一订单进行排序:

var items = JsonConvert.DeserializeObject<List<Order>>(jsonString);

//Adapted from LINQ: Order By Count of most common value
//https://stackoverflow.com/questions/20046563/linq-order-by-count-of-most-common-value
//Answer https://stackoverflow.com/a/20046812 by King King https://stackoverflow.com/users/1679602/king-king
var query = items
    //If order items aren't already sorted, you need to do so first.
    //use StringComparer.OrdinalIgnoreCase or StringComparer.Ordinal or StringComparer.CurrentCulture as required.
    .Select(i => i.order.OrderBy(s => s, StringComparer.Ordinal).ToArray()) 
    //Adapted from writing a custom comparer for linq groupby
    //https://stackoverflow.com/questions/37733773/writing-a-custom-comparer-for-linq-groupby
    //Answer https://stackoverflow.com/a/37734601 by Gert Arnold https://stackoverflow.com/users/861716/gert-arnold
    .GroupBy(s => s, new IEnumerableComparer<string [], string>())
    .OrderByDescending(g => g.Count())
    .Select(g => new Order { order = g.Key } );

var sortedItems = query.ToList();

演示小提琴here.

或者,如果你想保留重复而不是合并它们,你可以这样做:

var query = items
    //If order items aren't already sorted, you may need to do so first.
    //use StringComparer.OrdinalIgnoreCase or StringComparer.Ordinal or StringComparer.CurrentCulture as required.
    .Select(i => i.order.OrderBy(s => s, StringComparer.Ordinal).ToArray()) 
    //Adapted from writing a custom comparer for linq groupby
    //https://stackoverflow.com/questions/37733773/writing-a-custom-comparer-for-linq-groupby
    //Answer https://stackoverflow.com/a/37734601 by Gert Arnold https://stackoverflow.com/users/861716/gert-arnold
    .GroupBy(s => s, new IEnumerableComparer<string [], string>())
    .OrderByDescending(g => g.Count())
    .SelectMany(g => g)
    .Select(a => new Order { order = a });

演示小提琴#2 here.

注意事项:

  • 我使用两个泛型类型IEnumerableComparer&lt;TEnumerable, TElement&gt; : IEqualityComparer&lt;TEnumerable&gt; where TEnumerable : IEnumerable&lt;TElement&gt; 定义相等比较器,而不仅仅是IEnumerableComparer&lt;string&gt;,如Cédric Bignonthis answerIEqualityComparer for SequenceEqual 所示,以防止string [] 通过.GroupBy(s =&gt; s, new IEnumerableComparer&lt;string&gt;()) lambda 表达式中的类型推断,将键从向上转换为IEnumerable&lt;string&gt;

  • 如果您确定订单已经排序,或者["Order3", "Order1"]["Order1", "Order3"] 不同,则将i.order.OrderBy(s =&gt; s, StringComparer.Ordinal).ToArray() 替换为i.order

【讨论】:

    猜你喜欢
    • 2018-05-29
    • 2013-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多