Paire d'itération en C# ou fenêtre coulissante de l'agent recenseur
Si j'ai un IEnumerable comme:
string[] items = new string[] { "a", "b", "c", "d" };
Je voudrais en boucle par toutes les paires d'éléments consécutifs (fenêtre glissante de taille 2). Ce qui serait
("a","b"), ("b", "c"), ("c", "d")
Ma solution était est-ce
public static IEnumerable<Pair<T, T>> Pairs(IEnumerable<T> enumerable) {
IEnumerator<T> e = enumerable.GetEnumerator(); e.MoveNext();
T current = e.Current;
while ( e.MoveNext() ) {
T next = e.Current;
yield return new Pair<T, T>(current, next);
current = next;
}
}
//used like this :
foreach (Pair<String,String> pair in IterTools<String>.Pairs(items)) {
System.Out.PrintLine("{0}, {1}", pair.First, pair.Second)
}
Quand j'ai écrit ce code, je me demandais s'il existe déjà des fonctions dans l' .NET framework qui font la même chose et il n'est pas juste pour les paires, mais pour n'importe quel taille des n-uplets.
À mon humble avis, il devrait y avoir une façon agréable de faire ce genre de fenêtre coulissante opérations.
J'utilise C# 2.0 et je peux imaginer qu'avec C# 3.0 (w/LINQ) il n'y a plus (et plus agréable) façons de le faire, mais je suis principalement intéressé en C# 2.0 solutions. Cependant, j'apprécie aussi de C# 3.0 solutions.
- Cela semble comme il pourrait partager beaucoup de mise en œuvre avec Jon Skeet est
SmartEnumerator
qui vous indique si un élément est le dernier de la liste. msmvps.com/blogs/jon_skeet/archive/2007/07/27/... - Pour référence, cette fonction est appelée "Fenêtre" en F#: stackoverflow.com/questions/8874901/...
Vous devez vous connecter pour publier un commentaire.
Dans .NET 4 cela devient encore plus facile:-
input
deux fois - n'est pas un problème pour un tableau, mais si c'est paresseusement-évaluées qui pourrait être coûteux.Zip
peut être passé comme une méthode de groupe:…input.Zip(input.Skip(1), Tuple.Create);
Enumerable.Range(0, count)
que l'itérateur, j'ai dû augmenter le comte de ~1 million de dollars avant que le délai était perceptible, et ~10 millions de dollars avant c'était assez lent à me déranger. Encore, @dahlbyk solution élégante permet d'éviter cela, j'aimerais l'utiliser toute la journée. (L'ensemble de la point de méthodes d'extension est d'être en mesure de cacher le pas-très-lisible le code de la vue, de sorte priorités devrait être simple...).Plutôt que de demander à un n-uplet (la paire) type, pourquoi ne pas simplement accepter un sélecteur:
Qui vous permet de passer de l'objet intermédiaire si vous le souhaitez:
Ou vous pouvez utiliser un type anonyme:
yield return …(previous, previous = …)
. Le langage C# de garantir que le premier argument sera préparée avant le deuxième argument est évalué?Le plus simple est d'utiliser ReactiveExtensions
et de faire vous-même une méthode d'extension pour le kit bash cet ensemble
IEnumerable<T>
version deBuffer()
: github.com/Reactive-Extensions/Rx.NET/blob/...Un peu en retard à la fête, mais comme une alternative à toutes ces méthodes d'extension, on peut utiliser un "glissement"
Collection
de tenir (et de jeter) les données.Ici est celle que j'ai fini par faire aujourd'hui:
Utilisation:
Expansion sur le réponse précédente pour éviter de O(n2) approche en utilisant explicitement le passé itérateur:
Pour C# 2, avant les méthodes d'extension, chute de de la "ce" à partir du paramètre d'entrée et appel d'une méthode statique.
Enumerable.Range(1, 5).Tuples(2)
retourne{{1, 2}, {3, 4}, {5}}
au lieu de l'souhaité{{1, 2}, {2, 3}, {3, 4}, {4, 5}}
qui est une fenêtre coulissante.Juste pour des raisons de commodité, voici un sélecteur de-moins la version de @dahlbyk de réponse.
Voici ma solution à l'aide d'une Pile. Il est court et concis.
Pardonnez-moi si je suis surplombant quelque chose, mais pourquoi pas quelque chose de simple, comme une boucle for?:
C# 3.0 solution (désolé:)
Ce n'est pas le plus performant dans le monde, mais il est sûr agréable à regarder.
Vraiment, la seule chose ce qui en fait un de C# 3.0 est la solution .Skip.Prendre le construire, donc si vous venez de changer cela en ajoutant les éléments de cette gamme à une liste au lieu de cela, il devrait être d'or pour la 2.0. Cela dit, il n'est pas encore performant.
Suppléant
Pairs
mise en œuvre, à l'aide de la dernière paire de stocker la valeur précédente:Simple
Window
de mise en œuvre (seulement sans danger pour un usage privé, si l'appelant n'a pas d'enregistrer le tableau retourné; voir la note):Exemple d'utilisation:
F#
Seq
module définit les paires fonction deIEnumerable<T>
, mais cette fonction n'est pas dans l' .NET framework.Si elle était déjà dans le .NET framework, au lieu de retourner paires de il accepterait probablement un sélecteur de fonction en raison du manque de soutien pour les tuples dans des langages tels que C# et VB.
Je ne pense pas qu'aucune des réponses ici vraiment améliorer votre itérateur simple de mise en œuvre, ce qui me semblait le plus naturel pour moi (et l'affiche dahlbyk par les regards des choses!) trop.
Quelque chose comme ceci: