9

我正在清理 5 个文件以获取特定值。我预计不会有任何不同的值,但由于这是出于我自己的教育目的,我希望应用程序能够计算、比较和打印最受欢迎的值。

例如:

ArrayList arrName = new ArrayList();
arrName.Add("BOB")
arrName.Add("JOHN")
arrName.Add("TOM")
arrName.Add("TOM")
arrName.Add("TOM")

我想要的结果是TOM,但作为一个新手,我真的不知道如何前进。

非常感谢任何想法、建议或示例。谢谢你。

4

6 回答 6

4

如果可以使用 LINQ,您可以轻松地做到这一点,查询类似于

names.Distinct().OrderByDescending(s => names.Count(u => u == s))).FirstOrDefault();

它将返回具有最高计数的值,或default(Type). 在同等计数的情况下,它将返回第一个计数最高的。您可以将该方法放在带有泛型的扩展中以供一般使用。

class Program
{
    static void Main(string[] args)
    {

        IEnumerable<String> names = new String[] { "BOB", 
                                                   "JOHN", 
                                                   "TOM", 
                                                   "TOM", 
                                                   "TOM" };
        var res = names.Top(); //returns "TOM"
    }
}

public static class Extensions
{

    public static T Top<T>(this IEnumerable<T> values)
    {
        return values.Distinct().OrderByDescending(s => values.Count(u => u.Equals(s))).FirstOrDefault();
    }
}

如果您需要所有具有最高计数的值,例如如果您的列表是"BOB", "JOHN", "JOHN", "TOM", "TOM"我猜您可以使用此版本来返回 JOHN 和 TOM:

    public static IEnumerable<T> Top<T>(this IEnumerable<T> values)
    {
        List<T> ret = new List<T>();
        int max = -1;

        foreach (var val in values.Distinct())
        {
            int count = values.Count(t => t.Equals(val));

            if (count >= max)
            {
                if (count > max)
                {
                    ret.Clear();
                    max = count;
                }
                ret.Add(val); //stacks equivalent count, if applicable
            }
        }

        return ret;
    }
于 2010-01-24T06:35:59.887 回答
2

您没有指定您正在使用的 .Net / C# 版本,因此我将针对每个 C# 版本进行处理:v1、v2 和 v3。

C# V1:

class CountValueComparer : IComparer
{
    public int Compare(object x, object y)
    {
        DictionaryEntry left = (DictionaryEntry)x;
        DictionaryEntry right = (DictionaryEntry)y;

        return ((int)left.Value).CompareTo((int)right.Value);
    }
}

Hashtable counts = new Hashtable();

foreach(String value in arrName)
{
    if (counts.ContainsKey(value))
    {
        int valueCount = (int)counts[value];
        ++valueCount;
        counts[value] = valueCount;
    }
    else
    {
        counts[value] = 1;
    }
}

DictionaryEntry[] sorted = new DictionaryEntry[counts.Count];
counts.CopyTo(sorted, 0);
Array.Sort(sorted, new CountValueComparer());

foreach (DictionaryEntry entry in sorted)
{
    Console.Writeline("Name: {0}; Count: {1}", entry.Key, entry.Value);
}

C# V2:

class CountValueComparer : IComparer<KeyValuePair<String, int>>
{
    public int Compare(int x, int y)
    {
        return x.Value.CompareTo(y.Value);
    }
}

// if v2, use the List<T> class!
List<String> arrName = new List<String>();

arrName.Add("TOM");
// etc...

Dictionary<String, int> counts = new Dictionary<String, int>();

foreach(String value in arrName)
{
    int count;
    if (counts.TryGetValue(value, out count))
    {
        counts[value] = ++count;
    }
    else
    {
        counts[value] = 1;
    }
}

KeyValuePair<String, int>[] sorted = new KeyValuePair<String, int>[counts.Count];
counts.CopyTo(sorted, 0);
Array.Sort(sorted, new CountValueComparer());

C# V3:

// if v3, use the List<T> class!
var arrName = new List<String>();

arrName.Add("TOM");
// etc...

var counts = (from n in arrName 
              group n by n into g 
              select new { Name = g.Key, Count = g.Count() })
              .OrderByDescending(x => x.Count);
var top = counts.FirstOrDefault();
Console.WriteLine("Name: {0}; Count: {1}", top.Name, top.Count);
于 2010-01-24T06:00:00.403 回答
2

这是LINQ非常适合的任务。

首先,让我们定义我们在做什么:

  1. 按值对项目进行分组
  2. 计算每组
  3. 返回其组具有最高计数的项目

此查询实现了上述内容:

private string GetMostFrequent(IEnumerable<string> items)
{
    var itemsOrderedByCount =
        from item in items
        group item by item into itemGroup
        orderby itemGroup.Count() descending, itemGroup.Key
        select itemGroup.Key;

    return itemsOrderedByCount.FirstOrDefault();
}

实现读起来很像高级描述,是声明性语法的一个很好的副作用。以下是每个部分的快速说明:

from item in items

就像一个循环声明;item指循环变量。

group item by item into itemGroup

这将每个item基于其值的组。

orderby itemGroup.Count() descending, itemGroup.Key

这会计算每个组并对它们进行排序,以使最频繁的出现在第一位。如果有两个组具有相同的计数,则选择较小的值。(由于每个组包含所有相同的值,因此键是计数项。)

select itemGroup.Key

这表示对于每个组,我们只需要计数的项目。

return itemsOrderedByCount.FirstOrDefault();

这将获取有序列表中的第一项(计数最高的项)。如果原始序列为空,则返回 null。

用法:

var items = new[] { "BOB", "JOHN", "TOM", "TOM", "TOM" };

Assert.AreEqual("TOM", GetMostFrequent(items));
于 2010-01-24T06:16:23.347 回答
1
    public static string GetMostPopular(ArrayList vals)
    {
        IDictionary<string, int> dict = new Dictionary<string, int>();
        int mx = 0;
        string ret = "";
        foreach (string x in vals)
        {
            if (!dict.ContainsKey(x))
            {
                dict[x] = 1;
            }
            else
            {
                dict[x]++;
            }
            if (dict[x] > mx)
            {
                mx = dict[x];
                ret = x;
            }
        }
        return ret;
    }

    static void Main()
    {
        ArrayList arrName = new ArrayList();
        arrName.Add("BOB");
        arrName.Add("JOHN");
        arrName.Add("TOM");
        arrName.Add("TOM");
        arrName.Add("TOM");
        string ans = GetMostPopular(arrName);
        Console.WriteLine(ans);
    }
于 2010-01-24T05:55:02.023 回答
1

您可以使用 Dictionary (.NET 2.0+) 来保存每个值的重复计数:

Dictionary<string, int> counts = new Dictionary<string, int>();
foreach (string name in arrName) {
   int count;
   if (counts.TryGetValue(name, out count)) {
      counts[name] = count + 1;
   } else {
      counts.Add(name, 1);
   }
}

// and then look for the most popular value:

string mostPopular;
int max = 0;
foreach (string name in counts.Keys) {
   int count = counts[name];
   if (count > max) {
       mostPopular = name;
       max = count;
   }
}

// print it
Console.Write("Most popular value: {0}", mostPopular);

如果您使用的是 C# 3.0 (.NET 3.5 +),请使用:

var mostPopular = (from name in arrName.Cast<string>()
                   group name by name into g
                   orderby g.Count() descending
                   select g.Key).FirstOrDefault();

Console.Write("Most popular value: {0}", mostPopular ?? "None");
于 2010-01-24T06:00:16.227 回答
0

要通过循环,您可以使用foreach

foreach (string name in arrName) {
    Console.WriteLine(i);
}

要计算值,您可以使用 a Hashtable,它将键映射到值。键可以是名称,值可以是您在列表中看到该名称的次数。

Hashtable nameHash = new Hashtable();
foreach (string name in arrName) {
    if (!nameHash.ContainsKey(name)) {
        nameHash.Add(name, 1);
    }
    else {
        int num = nameHash[name];
        nameHash.Add(name, num + 1);
    }
}
于 2010-01-24T05:47:50.870 回答