比较/计算System.Collections.ArrayList中的值

时间:2010-01-24 05:43:00

标签: c# arraylist icomparable

我正在为特定值清理5个文件。我不期待任何不同的价值观,但因为这是出于我自己的教育目的,我希望应用程序能够计算,比较和打印最受欢迎的价值。

例如:

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

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

非常感谢任何想法,建议或例子。 谢谢。

6 个答案:

答案 0 :(得分:4)

如果可以使用LINQ,可以使用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;
    }

答案 1 :(得分: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);

答案 2 :(得分:2)

这是LINQ非常适合的任务。

首先,让我们来定义我们正在做的事情:

  1. 按值对项目进行分组
  2. 统计每个小组
  3. 返回组计数最高的项目
  4. 此查询实现上述内容:

    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));
    

答案 3 :(得分: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);
    }

答案 4 :(得分:1)

您可以使用词典(.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");

答案 5 :(得分:0)

要浏览循环,您可以使用foreach

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

要计算值,您可以使用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);
    }
}