2013-04-03 10 views
7

Załóżmy, że mamy tablicę danych:wybór elementów z macierzy zgodnie z indeksami podanymi w innej tablicy C#

double[] x = new double[N] {x_1, ..., x_N}; 

i tablicy o rozmiarze N zawierający etykiety odpowiadające elementom x:

int[] ind = new int[N] {i_1, ..., i_N}; 

Jaki jest najszybszy sposób wybrania wszystkich elementów z x, które mają określoną etykietę I zgodnie z ind?

Na przykład

x = {3, 2, 6, 2, 5} 
ind = {1, 2, 1, 1, 2} 
I = ind[0] = 1 

Wynik:

y = {3, 6, 2} 

Oczywiście, może być łatwo (ale nie efektywne i czyste) odbywa się z pętli, ale myślę, że nie powinno być tak, jak zrobić za pomocą .Where i lambdas..Thanks

EDIT:

Odpowiedź udzielona przez Marcina Juraszka jest całkowicie poprawna, dziękuję. Uprośniłem jednak pytanie w nadziei, że zadziała w mojej pierwotnej sytuacji. Można proszę spojrzeć, co jest problemem jeśli mamy typy generyczne:

T1[] xn = new T1[N] {x_1, ..., x_N}; 
T2[] ind = new T2[N] {i_1, ..., i_N}; 
T2 I = ind[0] 

stosując roztwór dostarczonego pojawia się błąd „Delegat«System.Func»nie wziąć 2 argumenty”:

T1[] y = xn.Where((x, idx) => ind[idx] == I).ToArray(); 

Dziękuję bardzo

Odpowiedz

14

Jak o tym:

var xs = new[] { 3, 2, 6, 2, 5 }; 
var ind = new[] { 1, 2, 1, 1, 2 }; 
var I = 1; 

var results = xs.Where((x, idx) => ind[idx] == I).ToArray(); 

wykorzystuje drugi, mniej popularne, Where przeciążenie:

Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>)

która ma indeks elementu dostępnego jako parametru bazowego (tzw idx w moim roztworu).

wersja Generic

public static T1[] WhereCorresponding<T1, T2>(T1[] xs, T2[] ind) where T2 : IEquatable<T2> 
{ 
    T2 I = ind[0]; 
    return xs.Where((x, idx) => ind[idx].Equals(I)).ToArray(); 
} 

Wykorzystanie

static void Main(string[] args) 
{ 
    var xs = new[] { 3, 2, 6, 2, 5 }; 
    var ind = new[] { 1, 2, 1, 1, 2 }; 

    var results = WhereCorresponding(xs, ind); 
} 

Generic + double wersja

public static T[] Test<T>(T[] xs, double[] ind) 
{ 
    double I = ind[0]; 

    return xs.Where((x, idx) => ind[idx] == I).ToArray(); 
} 
+0

myślał o użyciu ważny, ale do cholery: Krótszy niż to nie jest dostanie .. – flq

+0

Jest to bardzo miłe , dzięki. Czy mógłbyś spojrzeć na zmienioną wersję pytania? –

+1

Dla generycznych musisz mieć pewność, że zdefiniowano 'T2 == T2' (lub' T2.Equals (T2) ') - dodaj ogólne ograniczenie' where T2: IEquatable' – MarcinJuraszek

4

Jest to klasyczne zastosowanie dla Enumerable.Zip, które przebiega przez dwa wyliczenia równoległe do siebie. Za pomocą Zip możesz uzyskać wyniki za jednym razem.Poniżej znajduje całkowicie wpisać-agnostyk, choć używam int s i string s dla ilustracji:

int[] values = { 3, 2, 6, 2, 5 }; 
string[] labels = { "A", "B", "A", "A", "B" }; 
var searchLabel = "A"; 

var results = labels.Zip(values, (label, value) => new { label, value }) 
        .Where(x => x.label == searchLabel) 
        .Select(x => x.value); 
Powiązane problemy