Tôi tự hỏi nếu có chức năng .NET tích hợp để thay đổi từng giá trị trong một mảng dựa trên kết quả của một đại biểu được cung cấp. Ví dụ: nếu tôi có một mảng {1,2,3}
và một đại biểu trả về bình phương của mỗi giá trị, tôi muốn có thể chạy một phương thức lấy mảng và ủy quyền và trả về {1,4,9}
. Có bất cứ điều gì như thế này đã tồn tại chưa?C#: Thay đổi giá trị cho mỗi mục trong một mảng
Trả lời
Không phải là tôi biết (thay thế mỗi yếu tố chứ không phải chuyển sang một mảng mới hoặc trình tự), nhưng nó vô cùng dễ dàng để viết:
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]);
}
}
Sử dụng:
int[] values = { 1, 2, 3 };
values.ConvertInPlace(x => x * x);
Trong số nếu bạn không thực sự cần để thay đổi mảng hiện có, các câu trả lời khác được đăng bằng cách sử dụng Select
sẽ hoạt động tốt hơn. Hoặc phương pháp ConvertAll
hiện tại từ .NET 2:
int[] values = { 1, 2, 3 };
values = Array.ConvertAll(values, x => x * x);
Đây là tất cả giả định một mảng một chiều. Nếu bạn muốn bao gồm các mảng hình chữ nhật, nó sẽ phức tạp hơn, đặc biệt nếu bạn muốn tránh đấm bốc.
+1 cho ConvertAll mà thực sự là những gì OP hỏi cho "phương pháp lấy mảng và đại biểu, và trả về ..." –
Tôi không hiểu tại sao điều này lại đánh bại câu trả lời của Nathan cho câu trả lời được chấp nhận. Tôi đang thiếu gì? Chọn chính xác những gì anh ta cần, phải không? –
@Richard: Có thể câu trả lời của Nathan đã hoàn thành khi câu trả lời của tôi được chấp nhận, về mặt hỗ trợ đa chiều. Cách tôi đọc câu hỏi của OP để bắt đầu, tôi nghĩ anh ấy muốn sửa đổi mảng tại chỗ, mà chỉ có câu trả lời của tôi. Đối với mảng để chuyển đổi mảng, 'Array.ConvertAll' là hiệu quả hơn và không yêu cầu .NET 3.5. Nếu chỉ có một chuỗi là bắt buộc, 'Chọn' là tốt như đã đề cập trong câu trả lời của tôi. –
LINQ cung cấp hỗ trợ cho các dự báo theo phương pháp Select mở rộng:
var numbers = new[] {1, 2, 3};
var squares = numbers.Select(i => i*i).ToArray();
Bạn cũng có thể sử dụng một chút ít thông thạo Array.ConvertAll phương pháp:
var squares = Array.ConvertAll(numbers, i => i*i);
mảng Jagged thể được xử lý bằng cách xếp lồng các dự:
var numbers = new[] {new[] {1, 2}, new[] {3, 4}};
var squares = numbers.Select(i => i.Select(j => j*j).ToArray()).ToArray();
Mảng đa chiều phức tạp hơn một chút. Tôi đã viết phương thức mở rộng sau đây dự án mọi phần tử trong một mảng đa chiều bất kể thứ hạng của nó là gì.
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;
}
Phương pháp trên có thể được thử nghiệm với một loạt các cấp bậc 3 như sau:
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);
}
Ví dụ của bạn có lẽ nên sử dụng đại biểu thay vì chỉ định hàm trong lambda, để trả lời câu hỏi cụ thể hơn. –
Rất gọn gàng. Điều này có tính đến mảng đa chiều không? – JustOnePixel
À đúng rồi. Tôi đã tìm kiếm một phương pháp áp dụng hoặc một cái gì đó. Không bao giờ có thể nghĩ rằng nó được đặt tên là Chọn, nhưng tôi cho rằng nó đi cùng với cơ sở LINQ của tất cả các phương thức mở rộng thú vị. – jdmichal
Sử dụng System.Linq bạn có thể làm một cái gì đó như:
var newArray = arr.Select(x => myMethod(x)).ToArray();
truy vấn LINQ có thể dễ dàng giải quyết vấn đề này cho bạn - đảm bảo bạn đang tham chiếu System.Core.dll và có một số
using System.Linq;
tuyên bố. Ví dụ, nếu bạn đã có mảng của bạn trong một biến có tên numberArray, đoạn code sau sẽ cung cấp cho bạn biết chính xác những gì bạn đang tìm kiếm:
var squares = numberArray.Select(n => n * n).ToArray();
Trận chung kết "ToArray" cuộc gọi chỉ cần thiết nếu bạn thực sự cần một mảng và không phải là một số điện thoại có thể truy cập được <int>.
Tuyệt vời, cảm ơn. Điều này có tính đến mảng đa chiều không? – JustOnePixel
Không - cho điều đó, bạn muốn có một lựa chọn lồng nhau, như numberArrays.Select (as => as.Select (n => n * n) .ToArray()). ToArray(). Đối với một cách tiếp cận dễ đọc hơn, chỉ cần sử dụng hai vòng lặp lồng nhau. – Ben
bạn có thể sử dụng LINQ để thực hiện điều này theo cách viết tắt nhưng hãy cẩn thận nhớ rằng một foreach xảy ra bên dưới anyway.
int[] x = {1,2,3};
x = x.Select((Y) => { return Y * Y; }).ToArray();
Đây là giải pháp khác cho mảng M x N, trong đó M và N không được biết tại thời gian biên dịch.
// 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 có lẽ là một trong những tốt nhất tôi đã tìm thấy ... và tốt mà bạn đã cung cấp tín dụng cho các chàng trai đã viết nó (mặc dù các chàng hỏi rằng đã tức giận ra anh không áp dụng nó) –
- 1. Thêm giá trị cho một C# mảng
- 2. Thay đổi giá trị cho mục thuộc tính trong PropertyGrid
- 3. thay đổi giá trị const trong C
- 4. Thay đổi khóa mảng getResult cho giá trị khóa chính
- 5. Cách lấy giá trị cho mỗi khóa trong từ điển trong Mục tiêu-C?
- 6. Thay đổi một giá trị trong SQLite3
- 7. Thay đổi giá trị bên trong vòng lặp foreach không thay đổi giá trị trong mảng được lặp qua
- 8. cách thay đổi giá trị với mảng Ember.js forEach?
- 9. Mảng truy cập Javascript cho hàm theo giá trị, để mảng gốc không bị thay đổi
- 10. thay đổi giá trị của các phần tử mảng từ bên trong một hàm
- 11. khởi mảng trực tiếp với một giá trị không đổi
- 12. thay đổi giá trị của biến const trong C++
- 13. Tìm chỉ mục của một danh sách giá trị trong một mảng có nhiều mảng
- 14. Nhận giá trị chỉ mục mảng của 1000 mục lớn nhất trong một mảng bằng LINQ
- 15. Thay đổi các giá trị trong NSArray bằng dereferencing?
- 16. Chỉ định nhiều giá trị cho mảng trong C
- 17. Cách đặt giá trị cho các mảng trong c
- 18. Thay đổi giá trị href cho một siêu liên kết
- 19. C# Sao chép mảng theo giá trị
- 20. Python: Thay thế các giá trị trong một mảng
- 21. Giá trị nổi dưới dạng chỉ mục trong một mảng trong C++
- 22. Giá trị HEX trong Mục tiêu-C
- 23. mảng C++ - biểu thức phải có giá trị không đổi
- 24. Nhận các giá trị RGB cho mỗi pixel từ một hình ảnh thô trong C
- 25. giá trị thay đổi trong HashSet
- 26. Thay đổi giá trị trong một cột trong sqlite
- 27. Cách gán giá trị cho một mảng TCHAR
- 28. Android - Thay đổi giá trị trong strings.xml
- 29. Khởi tạo một mảng số nguyên với một giá trị duy nhất trong C# .NET
- 30. Thay thế tại chỗ nhanh chóng của một số giá trị trong một mảng nhiều mảng
Theo truyền thống, điều đó sẽ được gọi là Bản đồ; trong Linq nó được gọi là Chọn. –