2010-09-07 6 views
2

J'avais besoin d'un double [] scission en groupes d'éléments x par stride y renvoyant une liste. Assez basique ... une boucle et/ou un peu de linq et tout votre ensemble. Cependant, je n'ai pas passé beaucoup de temps sur les méthodes de vulgarisation et cela semblait être un bon candidat pour une pratique. La la version naïve retourne ce que je cherche dans mon application actuelle ....Comment rendre la méthode d'extension [exemple] plus générique/fonctionnelle/efficace?

(A) 
public static IList<T[]> Split<T>(this IEnumerable<T> source, int every, int take) 
{ 
    /*... throw E if X is insane ...*/ 
    var result = source 
       .Where ((t, i) => i % every == 0) 
       .Select((t, i) => source.Skip(i * every).Take(take).ToArray()) 
       .ToList(); 
    return result; 
} 

... le type de retour est une sorte de générique ... en fonction de votre définition de générique.

Je pense ...

(B)  
public static IEnumerable<IEnumerable<T>> Split<T> 
        (this IEnumerable<T> source,int every, int take){/*...*/} 

... est une meilleure solution ... peut-être.

Question (s):

  • Est (B) préféré ... Pourquoi?
  • Comment composeriez-vous (B) en tant que IList <T[]>?
  • Un avantage dans le refactoring? éventuellement deux méthodes qui pourraient être chaînées ou similaires.
  • L'approche est-elle sonore? ... ou ai-je manqué quelque chose de basique?

Commentaires, opinions et langage dur sont toujours appréciés.

Contexte d'utilisation: C# .Net 4.0

Répondre

3

B est probablement la meilleure option. Vraiment le changement majeur est que le consommateur du code a la possibilité d'en faire une liste en utilisant ToList() à la fin de votre méthode, au lieu d'être obligé de traiter avec une List (une IList, en fait, qui ne peut pas être itérée) .

Ceci a beaucoup d'avantages dans le chaînage de méthodes et l'utilisation générale. Il est facile de ToList() un énumérable, mais difficile à aller dans l'autre sens. Ainsi, vous pouvez appeler Select(). Split(). OrderBy() sur une liste et utiliser les résultats dans une instruction foreach sans avoir à faire en sorte que Linq parcourt tout le contenu en même temps.

Refactorisation à yield return valeurs uniques Vous pourriez obtenir un bonus de performance, mais puisque vous revenez simplement à l'itérateur que le Select vous a donné (ce qui donnera un élément à la fois), je ne pense pas que vous le fassiez obtenir beaucoup d'avantages à céder à travers lui-même.

1

En .Net 4, vous pouvez simplement changer le type de retour à IEnumerable<IEnumerable<T>> et cela fonctionnera. Avant de .Net 4, vous devez d'abord convertir les listes internes en IEnumerable en appelant simplement .Cast<IEnumerable<T>>() sur votre result avant de revenir.

+1

Pourquoi appeler 'Cast' au lieu de simplement supprimer les appels' ToArray' et 'ToList'? – jball

+0

@jball: Il y a une différence légitime si vous voulez exécuter la requête avec impatience. – Ani

+0

@Ani, il semble défier les attentes de LINQ et les méthodes d'extension pour faire une méthode d'extension qui s'exécute avec impatience. – jball

2

Je préférerais (B) car il semble plus flexible. Une façon de coulée de la sortie de la méthode (B) à un IList<T[]> est aussi simple que enchaînant .Select(x => x.ToArray()).ToList() à lui, par exemple,

var foo = 
    bar.Split(someEvery, someTake).Select(x => x.ToArray()).ToList();