Мне интересно, есть ли встроенная функция .NET для изменения каждого значения в массиве на основе результата предоставленного делегата. Например, если у меня был массив {1,2,3}
и делегат, который возвращает квадрат каждого значения, я хотел бы иметь возможность запускать метод, который принимает массив и делегировать, и возвращает {1,4,9}
. Что-то вроде этого уже существует?C#: Изменение значений для каждого элемента массива
ответ
Не то, что я знаю (замена каждого элемента, а не преобразовывать в новый массив или последовательности), но это невероятно легко написать:
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]);
}
}
Использование:
int[] values = { 1, 2, 3 };
values.ConvertInPlace(x => x * x);
Из конечно, если вы действительно не нуждаетесь нужно, чтобы изменить существующий массив, другие ответы, размещенные с использованием Select
, будут более функциональными. Или существующий ConvertAll
метод из .NET 2:
int[] values = { 1, 2, 3 };
values = Array.ConvertAll(values, x => x * x);
Это все при условии, один одномерный массив. Если вы хотите включить прямоугольные массивы, становится сложнее, особенно если вы хотите избежать бокса.
+1 для ConvertAll, который на самом деле является тем, что ОП запросил «метод, который принимает массив и делегирует его, и возвращает ...» –
Я не понимаю, почему это бьет ответ Натана для принятого ответа. Что мне не хватает? Выбор делает именно то, что ему нужно, нет? –
@ Рихард: Возможно, ответ Натана был таким же полным, когда мой ответ был принят с точки зрения многомерной поддержки. То, как я прочитал вопрос OP, чтобы начать, я думал, что он хочет изменить массив на месте, на который распространяется только мой ответ. Для преобразования массива в массив «Array.ConvertAll» более эффективен и не требует .NET 3.5. Если требуется только последовательность, 'Select' в порядке, как указано в моем ответе. –
LINQ обеспечивает поддержку для проекций с использованием метода Select расширения:
var numbers = new[] {1, 2, 3};
var squares = numbers.Select(i => i*i).ToArray();
Кроме того, можно использовать несколько менее свободно Array.ConvertAll метод:
var squares = Array.ConvertAll(numbers, i => i*i);
Зубчатые массивы могут быть обработаны путем вложения проекции:
var numbers = new[] {new[] {1, 2}, new[] {3, 4}};
var squares = numbers.Select(i => i.Select(j => j*j).ToArray()).ToArray();
Многомерные массивы немного сложнее. Я написал следующий метод расширения, который проектирует каждый элемент в многомерном массиве независимо от его ранга.
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;
}
Описанный выше метод может быть проверен с массивом ранга 3 следующим образом:
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);
}
Ваш пример должен, вероятно, использовать делегат, а не указывать функцию в лямбда, чтобы ответить на вопрос более конкретно. –
Очень аккуратный. Будет ли это учитывать многомерные массивы? – JustOnePixel
Ах, вот оно. Я искал метод Apply или что-то еще. Никогда бы не подумал, что это будет имя Select, но я полагаю, что это согласуется с базой LINQ всех интересных методов расширения. – jdmichal
Использование System.Linq вы могли бы сделать что-то вроде:
var newArray = arr.Select(x => myMethod(x)).ToArray();
LINQ запросы могут легко разрешите это для вас - убедитесь, что вы ссылаетесь на System.Core.dll и имеете
using System.Linq;
заявление. Например, если у вас был массив в переменной с именем numberArray, следующий код даст вам именно то, что вы ищете:
var squares = numberArray.Select(n => n * n).ToArray();
Последний вызов «ToArray» нужен только если вы на самом деле нужен массив , а не IEnumerable <int>.
Удивительный, спасибо. Будет ли это учитывать многомерные массивы? – JustOnePixel
Нет - для этого вам нужен вложенный выбор, например numberArrays.Select (as => as.Select (n => n * n) .ToArray()). ToArray(). Для возможно более читаемого подхода просто используйте два вложенных цикла. – Ben
вы можете использовать linq для выполнения этого в стенографии, но будьте осторожны, помните, что foreach встречается в любом случае.
int[] x = {1,2,3};
x = x.Select((Y) => { return Y * Y; }).ToArray();
Это еще одно решение для массивов M x N, где M и N не известны во время компиляции.
// 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);
}
}
Thats, наверное, лучший из тех, что я нашел ... и хорошо, что вы дали кредит парню, который его написал (хотя парень, который задал вопрос, разозлился, он не применил его) –
- 1. Изменение каждого элемента массива
- 2. Изменение цвета каждого элемента массива
- 3. Для каждого цикла: изменение значений вложенного массива
- 4. Переменная для каждого элемента массива
- 5. C++: Изменение значений массива для сопзЬ
- 6. $ .getScript для каждого элемента массива
- 7. цикла массива для каждого элемента
- 8. расчет для каждого элемента массива
- 9. цикл для каждого элемента массива?
- 10. Умножить два ключевых значений для каждого элемента массива
- 11. Метод массива для циклирования для каждого элемента
- 12. Выполнение различных вычислений для каждого элемента массива
- 13. C# вычесть число из каждого элемента массива?
- 14. Объединение каждого элемента массива
- 15. Изменение каждого слова массива
- 16. toString() для каждого элемента массива в Javascript
- 17. node js - многозадачность для каждого элемента массива
- 18. Добавление TextView для каждого элемента массива
- 19. Изменение имени элемента XML-массива элемента массива
- 20. Установка значений для каждого элемента управления ComboBox
- 21. Изменение значений для каждого объекта JSON
- 22. изменение значений в индексах массива C#
- 23. Программа C для увеличения каждого элемента массива, прошедшего
- 24. Изменение значений массива strucutres
- 25. Создайте запрос mysql для каждого элемента массива
- 26. mongoose - Выполнение запроса для каждого элемента массива
- 27. Создайте переменную для каждого элемента массива
- 28. Выберите строку информации для каждого элемента массива
- 29. Для каждого нечетного элемента массива PHP
- 30. Подведение итогов функции для каждого элемента массива
Традиционно это будет называться Карта; в Linq это называется Select. –