Uważam, że najbardziej optymalnym sposobem na zrobienie tego jest utworzenie "rozszerzenia podobnego do LINQ" za pomocą bloku iteratora. Pozwala to wykonać obliczenia wykonując pojedyncze przejście przez dane. Zauważ, że wydajność nie jest wcale ważna, jeśli chcesz wykonać obliczenia na małej liczbie liczb. Oczywiście to jest naprawdę twoja pętla w przebraniu.
static class Extensions {
public static IEnumerable<Tuple<T, Int32>> ToRunLengths<T>(this IEnumerable<T> source) {
using (var enumerator = source.GetEnumerator()) {
// Empty input leads to empty output.
if (!enumerator.MoveNext())
yield break;
// Retrieve first item of the sequence.
var currentValue = enumerator.Current;
var runLength = 1;
// Iterate the remaining items in the sequence.
while (enumerator.MoveNext()) {
var value = enumerator.Current;
if (!Equals(value, currentValue)) {
// A new run is starting. Return the previous run.
yield return Tuple.Create(currentValue, runLength);
currentValue = value;
runLength = 0;
}
runLength += 1;
}
// Return the last run.
yield return Tuple.Create(currentValue, runLength);
}
}
}
Należy pamiętać, że metoda rozszerzenia jest ogólna i można jej używać na dowolnym typie. Wartości są porównywane dla równości przy użyciu Object.Equals
. Jeśli jednak chcesz, możesz przekazać IEqualityComparer<T>
, aby umożliwić dostosowanie sposobu porównywania wartości.
Można użyć metody takie jak to:
var numbers = new[] { 4, 1, 1, 3, 3, 2, 5, 3, 2, 2 };
var runLengths = numbers.ToRunLengths();
Dla Ciebie danych wejściowych wynik będzie te krotki:
4 1
1 2
3 2
2 1
5 1
3 1
2 2
Trudno zobaczyć jak długość tablicy może być ustalona na poziomie 6, jeżeli przykładem jest 4, 1, 1, 3, 3, 2, 5, 3, 2, 2 ... –
Teraz sprawdź pytanie: proszę – sandeep
Dlaczego na wyjściach znajdują się zduplikowane klucze dla liczb "2" i "3"? Czy nie powinieneś raczej oczekiwać wyjścia "4 => 1, 1 => 2, 3 => 3, 2 => 3, 5 => 1"? –