2010-01-24 12 views
9

Estoy borrando 5 archivos para un valor específico. No anticipo valores diferentes, PERO dado que esto es para mis propios fines educativos, me gustaría que la aplicación cuente, compare e imprima el valor más popular.Comparar/contar valores en System.Collections.ArrayList

por ejemplo:

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

El resultado me gustaría va a ser TOM pero al ser un novato, yo realmente no sé cómo seguir adelante.

Cualquier pensamiento, sugerencia o ejemplo son muy apreciados. Gracias.

Respuesta

1

Puede utilizar un diccionario (.NET 2.0+) Para mantener el conteo repetido de cada valor:

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

Si estás usando C# 3.0 (.NET 3.5 +) a continuación, utilizar:

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

para moverse a través del bucle, se puede utilizar un foreach:

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

Y para contar los valores, se puede utilizar un Hashtable, que mapea claves a valores. La clave puede ser un nombre, y el valor puede ser cuántas veces ha visto ese nombre en la lista.

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

no se especificó la versión de .Net/C# que está utilizando, así que voy a tratar esto para cada versión de C#: v1, v2 y 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

Este es el tipo de tarea para la cual es LINQ muy adecuado.

En primer lugar, vamos a definir lo que estamos haciendo:

  1. Grupo de los artículos por valor
  2. contar cada grupo
  3. Vuelva el artículo cuyo grupo tiene el mayor número de

Este consulta implementa lo anterior:

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

La implementación se parece mucho a la descripción de alto nivel, un agradable efecto secundario de la sintaxis declarativa.Aquí hay una explicación rápida de cada parte:

from item in items 

es como una declaración de bucle; item se refiere a la variable de bucle.

group item by item into itemGroup 

Esto pone a cada uno item en un grupo con base en su valor.

orderby itemGroup.Count() descending, itemGroup.Key 

Esto cuenta cada grupo y los clasifica de manera tal que el más frecuente es el primero. Si hay dos grupos con el mismo conteo, se elige el valor menor. (A medida que cada grupo contiene todos los mismos valores, la clave es el elemento contado.)

select itemGroup.Key 

Esto dice que para cada grupo, sólo queremos que el elemento contado.

return itemsOrderedByCount.FirstOrDefault(); 

Esto toma el primer elemento de la lista ordenada (el que tiene el conteo más alto). Si la secuencia original está vacía, se devuelve null.

Uso:

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

Assert.AreEqual("TOM", GetMostFrequent(items)); 
4

Usted puede hacer esto con LINQ si se puede usar, con una consulta similar a

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

Se devolverá el valor con los más altos niveles, o default(Type) . En casos de recuentos equivalentes, devolverá el primero con el recuento más alto. Puede poner ese método en sus extensiones con genéricos para uso general.

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

Si necesita todos los valores que tienen los más altos niveles, como si la lista era "BOB", "JOHN", "JOHN", "TOM", "TOM" Creo que se puede utilizar esta versión en su lugar con el fin de devolver tanto Juan como 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; 
    }