2010-08-26 16 views
8

Im nuovo a LINQ così ho ancora lotta ....LINQ domanda ... necessità di ottenere elemento con valore minimo

Ho una collezione di comandi (ognuno ha una posizione di tipo Point). Ho bisogno di rimuovere il controllo con il valore Y più basso (controllo superiore) dalla raccolta.

Un esempio sarebbe più apprezzato!

+0

non con "SELECT", quindi è possibile modificare il titolo della domanda. – chiccodoro

+0

Forse intendi Y più basso (il massimo controllo)! È necessario ordinare la raccolta in ordine crescente per il valore Y e quindi selezionare il primo valore. – VinayC

+0

@chiccodoro thanx, non sapevo davvero cosa chiedere :) @VinayC sì, era troppo semplice per pensarci ... – no9

risposta

11

Qualcosa di simile a questo:

collection.Remove(collection.OrderBy(c => c.Location.Y).First()); 

L'ordinamento è piuttosto costoso, quindi a seconda del caso d'uso si potrebbe anche trovare l'oggetto con il valore più basso e quindi rimuoverlo:

collection.Remove(collection.First(c => c.Y == collection.Min(c2 => c2.Y))); 

Questo enumera l'elenco fino a tre volte, generalmente questo dovrebbe essere ancora più veloce di OrderBy, ma se le prestazioni sono importanti per te allora misura per primo.

+0

grazie per il tuo tempo Simon! – no9

+0

@Simon, non dovrebbe essere c.Location.Y? –

+0

@Nathan Koop: Dovrebbe essere ora, quando l'ho scritto la domanda dichiarata X :) –

6

Hai solo bisogno di trovare l'oggetto e rimuoverlo, questo è sicuro. Rimuovere è molto chiaro, ma mentre trovare, è possibile utilizzare il metodo di aggregazione come questo:

collection 
    .Remove(collection 
     .Aggregate((c1, c2) => c1.Point.Y < c2.Point.Y ? c1 : c2) 
    ) 
); 
+1

Questa è un'ottima risposta. Richiede solo una iterazione della collezione per trovare l'oggetto, piuttosto che due. Potrebbe essere facilmente utilizzato come punto di partenza per la creazione di un metodo di estensione come 'MinBy()' o 'MaxBy()'. – gilly3

-1
collection.Remove(collection.Min(c => c.Y)); 
+4

'collection.Min (c => c.Y)' restituisce la coordinata Y minima. Dato che 'collection.Remove' si aspetta un controllo, questa istruzione genererà un errore di compilazione. – kbrimington

0

Ricordate che LINQ acronimo di Language INtegreated Query. Cioè, è pensato per essere usato come strumento per l'interrogazione, non per che modifica le raccolte.

Detto questo, è possibile trovare il controllo che è necessario rimuovere utilizzando LINQ. Quindi rimuovilo semplicemente nel modo normale.

// Let's say controls is a ControlCollection 
var enumerable = controls.Cast<Control>(); 
int minimumY = enumerable.Min(c => c.Location.Y); 
Control topControl = enumerable.Where(c => c.Location.Y == minimumY); 

controls.Remove(topControl); 
+0

LINQ va bene per la modifica dei dati. Structured Query Language è anche per interrogare i dati, ovviamente, e se vuoi modificarlo devi usare qualcos'altro. – amaca

+0

@amaca: LINQ è "adatto per la modifica dei dati" nel senso che * può * essere utilizzato per questo scopo. Gli effetti collaterali non possono essere effettivamente garantiti, tranne che dal chiamante. Ma in realtà non è * destinato * a questo scopo. Per citare [Eric Lippert] (http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx): "Lo scopo di un'espressione è calcolare un valore, non causare un effetto collaterale. " –

3

L'ordine è più costoso. Ottieni il valore minimo.

var lowest = (from c in collection 
       where c.X == collection.Min(i => i.X) 
       select c).FirstOrDefault(); 
collection.Remove(c); 
0

Di seguito è riportato un metodo di estensione che consente di selezionare l'elemento min in contrapposizione al valore minimo. È possibile utilizzare in questo modo:

var lowest = collection.MinElement(x => x.Y);

allora si può solo rimuovere l'elemento con collection.Remove(lowest).

public static T MinElement<T>(this IEnumerable<T> source, Func<T, int> selector) { 
    if (source == null) { 
     throw new ArgumentNullException(nameof(source)); 
    } 

    int minValue = 0; 
    T minElement = default(T); 
    bool hasValue = false; 

    foreach (T s in source) { 
     int x = selector(s); 
     if (hasValue) { 
      if (x < minValue) { 
       minValue = x; 
       minElement = s; 
      } 
     } else { 
      minValue = x; 
      minElement = s; 
      hasValue = true; 
     } 
    } 

    if (hasValue) { 
     return minElement; 
    } 

    throw new InvalidOperationException("MinElement: No elements in sequence."); 
}