繁体   English   中英

如何使我的程序更有效和紧凑地找到阵列中第N个最常见的元素?

[英]How can I make my procedure for finding the Nth most frequent element in an array more efficient and compact?

这是我提出的解决方案的一个例子

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        int[] arr = new int[] { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 }; 
        var countlist = arr.Aggregate(new Dictionary<int,int>(), (D,i) => { 
                                        D[i] = D.ContainsKey(i) ? (D[i] + 1) : 1;
                                        return D; 
                                      })
                            .AsQueryable()
                            .OrderByDescending(x => x.Value)
                            .Select(x => x.Key)
                            .ToList();
        // print the element which appears with the second 
        // highest frequency in arr
        Console.WriteLine(countlist[2]); // should print 3
    }
}

至少,我想弄清楚如何

  • 将查询子句减少至少一个。 虽然我没有看到任何冗余,但这是LINQ查询的类型,我担心所有创建的中间结构的开销。

  • 弄清楚如何不在最后返回整个列表。 我只想要枚举序列中的第二个元素; 我不需要返回整个列表,以便从中获取单个元素。

int[] arr = new int[] { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 };

var lookup = arr.ToLookup(t => t);
var result = lookup.OrderByDescending(t => t.Count());

Console.WriteLine(result.ElementAt(1).Key);

我会这样做的。

int[] arr = new int[] { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 }; 


int rank =2; 
var item = arr.GroupBy(x=>x)          // Group them
   .OrderByDescending(x=>x.Count())   // Sort based on number of occurrences
   .Skip(rank-1)                      // Traverse to the position
   .FirstOrDefault();                 // Take the element


if(item!= null)
{
    Console.WriteLine(item.Key);
    // output - 3
}

我开始回答,看到上面的答案,并认为我会比较它们。

这里是小提琴

我在每个上面放了一个秒表,并拿出每个蜱的数量。 结果是:

Orignal: 50600
Berkser: 15970
Tommy: 3413
Hari: 1601
user3185569: 1571

看来@ user3185569的算法比Hari略快,比OP的原始版本快30-40倍。 注意是@ user3185569上面的答案看起来他缩放时更快。

更新:我上面发布的数字是在我的电脑上运行的。 使用.net小提琴执行会产生不同的结果:

Orignal: 46842
Berkser: 44620
Tommy: 11922
Hari: 13095
user3185569: 16491

让Berkser algortihm稍快一些。 我不完全清楚为什么会这样,因为我的目标是相同的.net版本。

我想出了下面的Linq和一本字典,因为你正在寻找的是一本有序的字典

        void Run()
    {
        int[] arr = new int[] { 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4 };
        int[] unique = arr.Distinct().ToArray();
        Dictionary<int, int> dictionary = unique.ToDictionary(k => k, v => 0);

        for(int i = 0; i < arr.Length; i++)
        {
            if(dictionary.ContainsKey(arr[i]))
            {
                dictionary[arr[i]]++;
            }
        }

        List<KeyValuePair<int, int>> solution = dictionary.ToList();
        solution.Sort((x,y)=>-1* x.Value.CompareTo(y.Value));
        System.Console.WriteLine(solution[2].Key);
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM