2010-11-07 5 views
3

En ce qui concerne this solution.Extraction de mots-clés Linq - portée d'extraction limite

Existe-t-il un moyen de limiter le nombre de mots-clés à prendre en compte? Par exemple, je voudrais que les premiers 1000 mots de texte soient calculés. Il y a une méthode "Take" dans Linq, mais elle sert un objectif différent - tous les mots seront calculés, et N enregistrements seront retournés. Quelle est la bonne alternative pour le faire correctement?

+0

'Take()' est un paresseux fonction! Cela ne fait pas tous les mots à calculer. Voir http://ideone.com/WwDwg par exemple. – Vlad

Répondre

2

appliquent simplement Take plus tôt - immédiatement après l'appel à Split:

var results = src.Split() 
       .Take(1000) 
       .GroupBy(...) // etc 
+0

Solution simple, mais semble bien fonctionner dans mon cas. Merci Jon! – SharpAffair

1

Enumerable.Take fait dans le flux de résultats fait sortir; il ne met pas entièrement sa source en mémoire tampon et ne retourne que le premier N. En regardant votre solution d'origine, le problème est que l'entrée à laquelle vous voulez faire un Take est String.Split. Malheureusement, cette méthode n'utilise aucune sorte d'exécution différée; il crée avec empressement un tableau de tous les 'splits' et le renvoie ensuite.

Par conséquent, la technique pour obtenir une séquence de diffusion en continu de mots de texte serait quelque chose comme:

var words = src.StreamingSplit() // you'll have to implement that    
       .Take(1000); 

Cependant, je note que le reste de votre requête est:

... 
.GroupBy(str => str) // group words by the value 
.Select(g => new 
      { 
       str = g.Key,  // the value 
       count = g.Count() // the count of that value 
       }); 

Notez que GroupBy est une opération de mise en tampon - vous pouvez vous attendre à ce que tous les 1000 mots de sa source finissent par être stockés quelque part dans le processus des groupes en cours d'acheminement.

Comme je le vois, les options sont:

  1. Si vous ne me dérange pas de passer par tout le texte pour fractionnement fins, alors src.Split().Take(1000) est très bien. L'inconvénient est le temps perdu (pour continuer à se séparer après qu'il n'est plus nécessaire) et l'espace gaspillé (pour stocker tous les mots dans un tableau, même si seulement les 1000 premiers) seront nécessaires. Toutefois, le reste de la requête ne fonctionnera pas plus de mots que nécessaire.
  2. Si vous ne pouvez pas vous permettre de faire (1) en raison de contraintes de temps/mémoire, passez à src.StreamingSplit().Take(1000) ou équivalent. Dans ce cas, aucun texte original ne sera traité après que 1000 mots ont été trouvés.

Prenez note que ces 1000 mots eux-mêmes finiront par se tamponnés par la clause GroupBy dans les deux cas.

+0

Merci de votre réponse détaillée. – SharpAffair

1

Eh bien, strictement parlant, LINQ est et non nécessairement va tout lire; Take s'arrêtera dès que possible. Le problème est que dans la question connexe, vous regardez Count, et il est difficile d'obtenir un nombre sans consommer toutes les données. De même, string.Split va regarder tout.

Mais si vous avez écrit une fonction paresseuse Split non-tampon (en utilisant le retour de rendement) et que vous vouliez les 1000 premiers mots uniques, puis

var words = LazySplit(text).Distinct().Take(1000); 

travaillerait