سؤال

أنا أقوم بتنظيف 5 ملفات للحصول على قيمة محددة. لا أتوقع أي قيم مختلفة ، ولكن بما أن هذا مخصص لأغراض تعليمية خاصة بي ، أود أن يحسب التطبيق القيمة الأكثر شعبية ومقارنة وطباعة.

علي سبيل المثال:

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

والنتيجة التي أود أن تكون ستكون توم ولكن كونها مبتدئًا ، فأنا لا أعرف حقًا كيفية المضي قدمًا.

أي أفكار أو اقتراحات أو أمثلة موضع تقدير كبير. شكرًا لك.

هل كانت مفيدة؟

المحلول

يمكنك استخدام قاموس (.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");

نصائح أخرى

يمكنك القيام بذلك بسهولة مع 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" أعتقد أنه يمكنك استخدام هذا الإصدار بدلاً من ذلك لإعادة كل من جون وتوم:

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

لم تحدد إصدار .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);

هذا هو نوع المهمة التي 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));
    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);
    }

للتحرك عبر الحلقة ، يمكنك استخدام ملف 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);
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top