2012-01-03 9 views
6

Estoy tratando de encontrar las principales apariciones de palabras en una cadena.Encuentra las palabras más altas que ocurren en una cadena C#

p. Ej.

Hello World This is a great world, This World is simply great 

de la cadena anterior Estoy tratando de calcular los resultados algo como sigue:

  • mundo, 3
  • grande, 2
  • hola, 1
  • esto, 2

pero ignorando las palabras con una longitud inferior a 3 caracteres s, p. is que ocurrió dos veces.

Traté de mirar en Dictionary<key, value> pares, traté de mirar en la extensión GroupBy de linq. Sé que la solución está en algún punto intermedio, pero no puedo entender el algoritmo y cómo hacerlo.

+4

¿Es esta una tarea? – dasblinkenlight

+0

Esto es similar: http://stackoverflow.com/questions/8630235/finding-the-number-of-occurences-strings-in-a-specific-format-occur-in-a-given-t/8630247#8630247 – Matthias

+0

@dasblinkenlight - No, esta no es una tarea, estoy tratando de extraer palabras clave meta y guardar en la base de datos para cada registro. – Thr3e

Respuesta

14

mediante LINQ y expresiones regulares

Regex.Split("Hello World This is a great world, This World is simply great".ToLower(), @"\W+") 
    .Where(s => s.Length > 3) 
    .GroupBy(s => s) 
    .OrderByDescending(g => g.Count()) 
+3

excelente respuesta, pero no recomendaría esta solución, sería mejor para él entender el uso del diccionario en lugar de regex o linq. solo digo. – DarthVader

+0

+1 La mejor respuesta ya que tiene en cuenta la puntuación ... – xandercoded

+0

@DarthVader Estoy de acuerdo con el nivel matemático. Desde la perspectiva de la programación, saber que LINQ es igual de valioso. –

0
string words = "Hello World This is a great world, This World is simply great".ToLower(); 

var results = words.Split(' ').Where(x => x.Length > 3) 
           .GroupBy(x => x) 
           .Select(x => new { Count = x.Count(), Word = x.Key }) 
           .OrderByDescending(x => x.Count); 

foreach (var item in results) 
    Console.WriteLine(String.Format("{0} occured {1} times", item.Word, item.Count)); 

Console.ReadLine(); 

Para obtener la palabra con el mayor número de ocurrencias:

results.First().Word;

+0

En lugar de 'Word = x.First()', puedes acceder a la clave del grupo a través de 'Word = x.Key'. –

+0

Gracias @TathamOddie no sabía eso - * btw *, gracias por FormsAuthenticationExtensions;) – xandercoded

3
const string input = "Hello World This is a great world, This World is simply great"; 
var words = input 
    .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) 
    .Where(w => w.Length >= 3) 
    .GroupBy(w => w) 
    .OrderByDescending(g => g.Count()); 

foreach (var word in words) 
    Console.WriteLine("{0}x {1}", g.Count(), word.Key); 

// 2x World 
// 2x This 
// 2x great 
// 1x Hello 
// 1x world, 
// 1x simply 

No es perfecto, ya que no recorta la coma , pero le muestra cómo hacer la agrupación y el filtrado al menos.

3

Así que evitaría LINQ y Regex y similares ya que parece que estás tratando de encontrar un algoritmo y entiendo que esto no utiliza alguna función para hacerlo por ti.

No es que esas no sean soluciones válidas. Son. Seguro.

intentar algo como esto

Dictionary<string, int> dictionary = new Dictionary<string, int>(); 

string sInput = "Hello World, This is a great World. I love this great World"; 
sInput = sInput.Replace(",", ""); //Just cleaning up a bit 
sInput = sInput.Replace(".", ""); //Just cleaning up a bit 
string[] arr = sInput.Split(' '); //Create an array of words 

foreach (string word in arr) //let's loop over the words 
{ 
    if (word.Length >= 3) //if it meets our criteria of at least 3 letters 
    { 
     if (dictionary.ContainsKey(word)) //if it's in the dictionary 
      dictionary[word] = dictionary[word] + 1; //Increment the count 
     else 
      dictionary[word] = 1; //put it in the dictionary with a count 1 
    } 
} 

foreach (KeyValuePair<string, int> pair in dictionary) //loop through the dictionary 
    Response.Write(string.Format("Key: {0}, Pair: {1}<br />",pair.Key,pair.Value)); 
+0

Puede hacer string sInput = "Hola mundo, este es un gran mundo. Amo este gran mundo"; string sInput = "Hola mundo, este es un gran mundo. Amo este gran mundo" .ToLower(); para que no distinga entre mayúsculas y minúsculas. Personalmente, me gusta la distinción entre mayúsculas y minúsculas, ya que puede decir los nombres propios y el comienzo de una oración, incluso sin puntuación, para que no se pierda nada. En el lado negativo Mundo y mundo no son iguales. – Jordan

+0

+1 Bonito puesto de enseñanza. Daría otro +1 por comentarios si pudiera. –

+1

En cuanto a su comentario sobre la carcasa, hay una solución mucho más sencilla: crear el diccionario utilizando un comparador insensible a mayúsculas y minúsculas: 'var dictionary = new Dictionary (StringComparer.InvariantCultureIgnoreCase);' –

2

que escribir un procesador de cadena class.You puede utilizarlo.

Ejemplo:

metaKeywords = bodyText.Process(blackListWords: prepositions).OrderByDescending().TakeTop().GetWords().AsString(); 

Clase:

public static class StringProcessor 
{ 
    private static List<String> PrepositionList; 

    public static string ToNormalString(this string strText) 
    { 
     if (String.IsNullOrEmpty(strText)) return String.Empty; 
     char chNormalKaf = (char)1603; 
     char chNormalYah = (char)1610; 
     char chNonNormalKaf = (char)1705; 
     char chNonNormalYah = (char)1740; 
     string result = strText.Replace(chNonNormalKaf, chNormalKaf); 
     result = result.Replace(chNonNormalYah, chNormalYah); 
     return result; 
    } 

    public static List<KeyValuePair<String, Int32>> Process(this String bodyText, 
     List<String> blackListWords = null, 
     int minimumWordLength = 3, 
     char splitor = ' ', 
     bool perWordIsLowerCase = true) 
    { 
     string[] btArray = bodyText.ToNormalString().Split(splitor); 
     long numberOfWords = btArray.LongLength; 
     Dictionary<String, Int32> wordsDic = new Dictionary<String, Int32>(1); 
     foreach (string word in btArray) 
     { 
      if (word != null) 
      { 
       string lowerWord = word; 
       if (perWordIsLowerCase) 
        lowerWord = word.ToLower(); 
       var normalWord = lowerWord.Replace(".", "").Replace("(", "").Replace(")", "") 
        .Replace("?", "").Replace("!", "").Replace(",", "") 
        .Replace("<br>", "").Replace(":", "").Replace(";", "") 
        .Replace("،", "").Replace("-", "").Replace("\n", "").Trim(); 
       if ((normalWord.Length > minimumWordLength && !normalWord.IsMemberOfBlackListWords(blackListWords))) 
       { 
        if (wordsDic.ContainsKey(normalWord)) 
        { 
         var cnt = wordsDic[normalWord]; 
         wordsDic[normalWord] = ++cnt; 
        } 
        else 
        { 
         wordsDic.Add(normalWord, 1); 
        } 
       } 
      } 
     } 
     List<KeyValuePair<String, Int32>> keywords = wordsDic.ToList(); 
     return keywords; 
    } 

    public static List<KeyValuePair<String, Int32>> OrderByDescending(this List<KeyValuePair<String, Int32>> list, bool isBasedOnFrequency = true) 
    { 
     List<KeyValuePair<String, Int32>> result = null; 
     if (isBasedOnFrequency) 
      result = list.OrderByDescending(q => q.Value).ToList(); 
     else 
      result = list.OrderByDescending(q => q.Key).ToList(); 
     return result; 
    } 

    public static List<KeyValuePair<String, Int32>> TakeTop(this List<KeyValuePair<String, Int32>> list, Int32 n = 10) 
    { 
     List<KeyValuePair<String, Int32>> result = list.Take(n).ToList(); 
     return result; 
    } 

    public static List<String> GetWords(this List<KeyValuePair<String, Int32>> list) 
    { 
     List<String> result = new List<String>(); 
     foreach (var item in list) 
     { 
      result.Add(item.Key); 
     } 
     return result; 
    } 

    public static List<Int32> GetFrequency(this List<KeyValuePair<String, Int32>> list) 
    { 
     List<Int32> result = new List<Int32>(); 
     foreach (var item in list) 
     { 
      result.Add(item.Value); 
     } 
     return result; 
    } 

    public static String AsString<T>(this List<T> list, string seprator = ", ") 
    { 
     String result = string.Empty; 
     foreach (var item in list) 
     { 
      result += string.Format("{0}{1}", item, seprator); 
     } 
     return result; 
    } 

    private static bool IsMemberOfBlackListWords(this String word, List<String> blackListWords) 
    { 
     bool result = false; 
     if (blackListWords == null) return false; 
     foreach (var w in blackListWords) 
     { 
      if (w.ToNormalString().Equals(word)) 
      { 
       result = true; 
       break; 
      } 
     } 
     return result; 
    } 
} 
Cuestiones relacionadas