Mi chiedo se non ci sia funzionalità .NET integrata per modificare ciascun valore in un array in base al risultato di un delegato fornito. Ad esempio, se avessi un array {1,2,3}
e un delegato che restituisce il quadrato di ciascun valore, mi piacerebbe essere in grado di eseguire un metodo che prende l'array e delegare e restituisce {1,4,9}
. Esiste già qualcosa di simile?C#: modifica dei valori per ogni elemento di un array
risposta
Non che io sappia (sostituzione di ogni elemento, piuttosto che la conversione a un nuovo array o sequenza), ma è incredibilmente facile da scrivere:
public static void ConvertInPlace<T>(this IList<T> source, Func<T, T> projection)
{
for (int i = 0; i < source.Count; i++)
{
source[i] = projection(source[i]);
}
}
Usa:
int[] values = { 1, 2, 3 };
values.ConvertInPlace(x => x * x);
Di Certo che se proprio non lo è occorre cambiare la matrice esistente, le altre risposte pubblicate utilizzando Select
sarebbero più funzionali. O il ConvertAll
metodo esistente da NET 2:
int[] values = { 1, 2, 3 };
values = Array.ConvertAll(values, x => x * x);
Questo è tutto ipotizzando una matrice unidimensionale. Se vuoi includere array rettangolari, diventa più complicato, soprattutto se vuoi evitare la boxe.
+1 per ConvertAll che in realtà è ciò che l'OP chiedeva "metodo che prende l'array e delegare e restituisce ..." –
Non capisco perché questo batte la risposta di Nathan per la risposta accettata. Cosa mi manca? Select fa esattamente ciò di cui ha bisogno, no? –
@Richard: È possibile che la risposta di Nathan sia completa quando la mia risposta è stata accettata, in termini di supporto multidimensionale. Il modo in cui ho letto la domanda dell'OP per cominciare, ho pensato che voleva modificare la matrice in atto, che copre solo la mia risposta. Per la conversione da matrice ad array, 'Array.ConvertAll' è più efficiente e non richiede .NET 3.5. Se è richiesta solo una sequenza, 'Select' va bene come menzionato nella mia risposta. –
LINQ fornisce supporto per proiezioni utilizzando il metodo Select estensione:
var numbers = new[] {1, 2, 3};
var squares = numbers.Select(i => i*i).ToArray();
È anche possibile utilizzare il leggermente meno scorrevole Array.ConvertAll metodo:
var squares = Array.ConvertAll(numbers, i => i*i);
array frastagliati possono essere trattati con l'annidamento proiezioni:
var numbers = new[] {new[] {1, 2}, new[] {3, 4}};
var squares = numbers.Select(i => i.Select(j => j*j).ToArray()).ToArray();
Gli array multidimensionali sono un po 'più complessi. Ho scritto il seguente metodo di estensione che proietta ogni elemento in una matrice multidimensionale, indipendentemente dal suo grado.
static Array ConvertAll<TSource, TResult>(this Array source,
Converter<TSource, TResult> projection)
{
if (!typeof (TSource).IsAssignableFrom(source.GetType().GetElementType()))
{
throw new ArgumentException();
}
var dims = Enumerable.Range(0, source.Rank)
.Select(dim => new {lower = source.GetLowerBound(dim),
upper = source.GetUpperBound(dim)});
var result = Array.CreateInstance(typeof (TResult),
dims.Select(dim => 1 + dim.upper - dim.lower).ToArray(),
dims.Select(dim => dim.lower).ToArray());
var indices = dims
.Select(dim => Enumerable.Range(dim.lower, 1 + dim.upper - dim.lower))
.Aggregate(
(IEnumerable<IEnumerable<int>>) null,
(total, current) => total != null
? total.SelectMany(
item => current,
(existing, item) => existing.Concat(new[] {item}))
: current.Select(item => (IEnumerable<int>) new[] {item}))
.Select(index => index.ToArray());
foreach (var index in indices)
{
var value = (TSource) source.GetValue(index);
result.SetValue(projection(value), index);
}
return result;
}
Il metodo di cui sopra può essere testato con una serie di rango 3 come segue:
var source = new int[2,3,4];
for (var i = source.GetLowerBound(0); i <= source.GetUpperBound(0); i++)
for (var j = source.GetLowerBound(1); j <= source.GetUpperBound(1); j++)
for (var k = source.GetLowerBound(2); k <= source.GetUpperBound(2); k++)
source[i, j, k] = i*100 + j*10 + k;
var result = (int[,,]) source.ConvertAll<int, int>(i => i*i);
for (var i = source.GetLowerBound(0); i <= source.GetUpperBound(0); i++)
for (var j = source.GetLowerBound(1); j <= source.GetUpperBound(1); j++)
for (var k = source.GetLowerBound(2); k <= source.GetUpperBound(2); k++)
{
var value = source[i, j, k];
Debug.Assert(result[i, j, k] == value*value);
}
L'esempio dovrebbe probabilmente utilizzare un delegato piuttosto che specificare la funzione nel lambda, per rispondere alla domanda in modo più specifico. –
Molto pulito. Questo prenderà in considerazione gli array multidimensionali? – JustOnePixel
Ah, eccolo. Stavo cercando un metodo Apply o qualcosa del genere. Non avrei mai pensato che si chiamasse Select, ma suppongo che si accompagni alla base LINQ di tutti i divertenti metodi di estensione. – jdmichal
Utilizzando System.Linq si potrebbe fare qualcosa di simile:
var newArray = arr.Select(x => myMethod(x)).ToArray();
query LINQ potrebbe facilmente risolvi questo problema: assicurati di fare riferimento a System.Core.dll e disponi di uno
using System.Linq;
dichiarazione. Ad esempio, se si ha l'array in una variabile denominata numberArray, il seguente codice darebbe esattamente quello che stai cercando:
var squares = numberArray.Select(n => n * n).ToArray();
La chiamata finale "ToArray" è necessaria solo se è effettivamente necessario un allineamento e non un oggetto IEnumerable <int>.
Fantastico, grazie. Questo prenderà in considerazione gli array multidimensionali? – JustOnePixel
No - per questo, si desidera una selezione nidificata, come numberArrays.Select (as => as.Select (n => n * n) .ToArray()). ToArray(). Per un approccio probabilmente più leggibile, basta usare due anelli annidati. – Ben
è possibile utilizzare linq per eseguire questa operazione in stenografia, ma fare attenzione ricordare che un foreach si verifica sotto comunque.
int[] x = {1,2,3};
x = x.Select((Y) => { return Y * Y; }).ToArray();
Ecco un'altra soluzione per N matrici M x, dove M e N non sono noti al momento della compilazione.
// credit: https://blogs.msdn.microsoft.com/ericlippert/2010/06/28/computing-a-cartesian-product-with-linq/
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
foreach (var sequence in sequences)
{
// got a warning about different compiler behavior
// accessing sequence in a closure
var s = sequence;
result = result.SelectMany(seq => s, (seq, item) => seq.Concat<T>(new[] { item }));
}
return result;
}
public static void ConvertInPlace(this Array array, Func<object, object> projection)
{
if (array == null)
{
return;
}
// build up the range for each dimension
var dimensions = Enumerable.Range(0, array.Rank).Select(r => Enumerable.Range(0, array.GetLength(r)));
// build up a list of all possible indices
var indexes = EnumerableHelper.CartesianProduct(dimensions).ToArray();
foreach (var index in indexes)
{
var currentIndex = index.ToArray();
array.SetValue(projection(array.GetValue(currentIndex)), currentIndex);
}
}
Questo è probabilmente il migliore che ho trovato ... e buono che hai dato il merito al ragazzo che lo ha scritto (anche se il ragazzo che ha fatto la domanda si è incazzato non l'ha applicato) –
- 1. ottieni un array di KEY per ogni elemento sotto jsonarray
- 2. Stampa di una virgola (,) dopo ogni elemento in un array
- 3. Foreach copia ogni elemento se è un array di strutture?
- 4. Seleziona/associa ogni elemento di un array Powershell a un nuovo array
- 5. Modifica dei valori in HashSet
- 6. Numpy: per ogni elemento in un array, trovare l'indice in un altro array
- 7. Modifica dei valori dei passaggi nella barra di ricerca?
- 8. Loop per ogni elemento in un elenco
- 9. Visualizzazione dei valori di modifica nell'etichetta JavaFx
- 10. Come si seleziona ogni ennesimo elemento in un array?
- 11. Modifica dei valori delle variabili nelle sottoclassi?
- 12. Il più grande elemento presente sul lato destro di ogni elemento di un array
- 13. Controllare se ogni elemento in un array NumPy è in un altro array
- 14. modifica dei vaid POSIXct al primo giorno di ogni settimana
- 15. C# 4.0: Parametri dei parametri come valori predefiniti come array
- 16. Modifica dei valori di più colonne di un dataframe panda utilizzando colonna valori noti
- 17. lunghezza MATLAB di ogni elemento in array di celle
- 18. Lodash per Ogni array associativo
- 19. Modifica sottostante array di caratteri di un oggetto C++ stringa
- 20. Modificare l'ultimo elemento in un array
- 21. Verificare se ogni elemento in un array si trova in un secondo array
- 22. Android OverlayItem.setMarker(): modifica l'indicatore per un elemento
- 23. Come quadrare ogni elemento di un array nella classe Array in Ruby?
- 24. modifica di valori di array in modo ricorsivo in PHP
- 25. C'è un modo per dedurre un tipo di un singolo elemento di un array in C++
- 26. modo più breve per passare ogni elemento di un array a una funzione
- 27. Modifica dei valori del dizionario in un ciclo foreach
- 28. Aggiornamento di un campo in ogni elemento di un array di strutture Matlab
- 29. Elemento di picco in un array in c
- 30. Modifica dei valori dell'array nella funzione - Assemblaggio in linea
Tradizionalmente, si chiamerebbe Mappa; in Linq si chiama Select. –