Thêm mục mới trong mảng hiện có trong c # .net


134

Làm cách nào để thêm mục mới trong mảng chuỗi hiện có trong C # .net?

Tôi cần phải bảo tồn dữ liệu hiện có.

Câu trả lời:


121

Tôi sẽ sử dụng Danh sách nếu bạn cần một mảng có kích thước động:

List<string> ls = new List<string>();
ls.Add("Hello");

27
Và nếu được yêu cầu, hãy thực hiện ls.ToArray () ở cuối
Narayana

2
Sử dụng một cơ chế khác hơn hỏi trong câu hỏi không phải là một câu trả lời.
dùng11909

@ user2190035: Không chắc chắn nơi bạn có ý tưởng đó và 111 người được nêu lên sẽ không đồng ý với bạn. Nếu bạn biết một cách tốt hơn để mở rộng một mảng thì bằng mọi cách, hãy đăng nó. Tôi nghi ngờ việc phân bổ lại và sao chép thủ công của bạn sẽ tốt hơn so với việc sử dụng Danh sách. Đôi khi câu trả lời là "đừng làm vậy."
Ed S.

@ EdS. Câu hỏi là, làm thế nào để thêm một mục vào một chuỗi chuỗi hiện có , nhưng câu trả lời này hoàn toàn không có mảng nào, thay vào đó nó tạo ra một Danh sách mới <>. Trong ứng dụng của mình, tôi không thể thay đổi loại thành Danh sách <>, do đó tôi phải thay đổi kích thước một mảng (tạo một bản sao ...). Câu trả lời của Ali Ersöz đã giúp tôi.
user11909

@ user2190035: Vô số <T> .ToArray (). Tôi viết C # mỗi ngày và tôi chưa bao giờ phải thay đổi kích thước một mảng như thế.
Ed S.

100

Đó có thể là một giải pháp;

Array.Resize(ref array, newsize);
array[newsize - 1] = "newvalue"

Nhưng đối với mảng kích thước động, tôi cũng muốn liệt kê.


@Konrad, điều đó chắc chắn sẽ bảo tồn dữ liệu trong mảng.
Ali Ersöz

1
Điều này không phù hợp với nhiều lần gọi. bởi vì chức năng 'Thay đổi kích thước' có hiệu suất rất lớn. lỗi trong một hoặc hai lần, điều này là rất tốt.
quảng cáo

53

Sử dụng LINQ:

arr = (arr ?? Enumerable.Empty<string>()).Concat(new[] { newitem }).ToArray();

Tôi thích sử dụng điều này vì nó là một lớp lót và rất thuận tiện để nhúng vào câu lệnh chuyển đổi, câu lệnh if đơn giản hoặc truyền làm đối số.

BIÊN TẬP:

Một số người không thích new[] { newitem }vì nó tạo ra một mảng nhỏ, một mục, tạm thời. Đây là một phiên bản sử dụng Enumerable.Repeatkhông yêu cầu tạo bất kỳ đối tượng nào (ít nhất là không phải trên bề mặt - Trình lặp .NET có thể tạo ra một loạt các đối tượng máy trạng thái dưới bảng).

arr = (arr ?? Enumerable.Empty<string>()).Concat(Enumerable.Repeat(newitem,1)).ToArray();

Và nếu bạn chắc chắn rằng mảng không bao giờ nullbắt đầu, bạn có thể đơn giản hóa nó thành:

arr.Concat(Enumerable.Repeat(newitem,1)).ToArray();

Lưu ý rằng nếu bạn muốn thêm các mục vào một bộ sưu tập theo thứ tự, Listcó thể là cấu trúc dữ liệu bạn muốn, không phải là một mảng để bắt đầu.


1
+1 rất đẹp. Tôi có mã tương tự như một phương pháp mở rộng chung. Tôi đã bao gồm mã trong câu trả lời này: stackoverflow.com/a/11035286/673545
dblood

Điều này rất hữu ích khi tìm thấy nó trong khi tìm kiếm "cách nối vào một mảng trong một dòng mã trong c #" - hy vọng nhận xét này là đủ để tìm lại lần sau.
gary

28

Câu hỏi rất cũ, nhưng vẫn muốn thêm điều này.

Nếu bạn đang tìm kiếm một lớp lót, bạn có thể sử dụng mã dưới đây. Nó kết hợp hàm tạo danh sách chấp nhận cú pháp khởi tạo vô số và "mới" (kể từ khi đặt câu hỏi).

myArray = new List<string>(myArray) { "add this" }.ToArray();

26

Mảng trong C # là bất biến , ví dụ string[], int[]. Điều đó có nghĩa là bạn không thể thay đổi kích thước chúng. Bạn cần tạo một mảng hoàn toàn mới.

Đây là mã cho Array.Resize :

public static void Resize<T>(ref T[] array, int newSize)
{
    if (newSize < 0)
    {
        throw new ArgumentOutOfRangeException("newSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
    }
    T[] sourceArray = array;
    if (sourceArray == null)
    {
        array = new T[newSize];
    }
    else if (sourceArray.Length != newSize)
    {
        T[] destinationArray = new T[newSize];
        Copy(sourceArray, 0, destinationArray, 0, (sourceArray.Length > newSize) ? newSize : sourceArray.Length);
        array = destinationArray;
    }
}

Như bạn có thể thấy nó tạo ra một mảng mới với kích thước mới, sao chép nội dung của mảng nguồn và đặt tham chiếu đến mảng mới. Gợi ý cho điều này là từ khóa ref cho tham số đầu tiên.

Có những danh sách có thể tự động phân bổ các vị trí mới cho các mục mới. Đây là ví dụ Danh sách <T> . Chúng chứa các mảng bất biến và thay đổi kích thước chúng khi cần (Danh sách <T> không phải là triển khai danh sách được liên kết!). ArrayList là điều tương tự không có Generics (với mảng Object ).

LinkedList <T> là một triển khai danh sách liên kết thực sự. Thật không may, bạn chỉ có thể thêm các phần tử LinkListNode <T> vào danh sách, vì vậy bạn phải bọc các phần tử danh sách của riêng bạn vào loại nút này. Tôi nghĩ rằng việc sử dụng nó là không phổ biến.


Tôi nghĩ bạn có nghĩa là Array.Copy
user123456

2
Chỉ trả lời cung cấp một số thông tin về lý do không thể và không chỉ đề xuất sử dụng danh sách ...
Gilad Green

Tôi tin rằng Aray.Resizecó thể thay đổi kích thước một mảng mà không mất nội dung của nó. docs.microsoft.com/en-us/dotnet/api/ từ
AbdelAziz AbdelLatef

25
 Array.Resize(ref youur_array_name, your_array_name.Length + 1);
 your_array_name[your_array_name.Length - 1] = "new item";

7

Bạn có thể mở rộng câu trả lời do @Stephen Chung cung cấp bằng cách sử dụng logic dựa trên LINQ của anh ấy để tạo phương thức mở rộng bằng cách sử dụng loại chung.

public static class CollectionHelper
{
    public static IEnumerable<T> Add<T>(this IEnumerable<T> sequence, T item)
    {
        return (sequence ?? Enumerable.Empty<T>()).Concat(new[] { item });
    }

    public static T[] AddRangeToArray<T>(this T[] sequence, T[] items)
    {
        return (sequence ?? Enumerable.Empty<T>()).Concat(items).ToArray();
    }

    public static T[] AddToArray<T>(this T[] sequence, T item)
    {
        return Add(sequence, item).ToArray();
    }

}

Sau đó bạn có thể gọi nó trực tiếp trên mảng như thế này.

    public void AddToArray(string[] options)
    {
        // Add one item
        options = options.AddToArray("New Item");

        // Add a 
        options = options.AddRangeToArray(new string[] { "one", "two", "three" });

        // Do stuff...
    }

Phải thừa nhận rằng phương thức AddRangeToArray () có vẻ hơi quá mức vì bạn có cùng chức năng với Concat () nhưng theo cách này, mã kết thúc có thể "hoạt động" với mảng trực tiếp trái ngược với điều này:

options = options.Concat(new string[] { "one", "two", "three" }).ToArray();

Cảm ơn bạn, Điều này rất hữu ích, tôi đã thêm một tùy chọn để xóa một mục (Tôi hy vọng rằng điều này là ổn với bạn).
Tal Segal

@TalSegal bạn được chào đón, niềm vui của tôi. Sử dụng mã khi bạn thấy phù hợp!
dblood

6

Tốt hơn là giữ cho Array không thay đổi và có kích thước cố định.

bạn có thể mô phỏng Addtheo Extension MethodIEnumerable.Concat()

public static class ArrayExtensions
    {
        public static string[] Add(this string[] array, string item)
        {
            return array.Concat(new[] {item}).ToArray();
        }
    }

5

nếu bạn đang làm việc rất nhiều với các mảng và không liệt kê vì một số lý do, phương thức trả về chung được gõ này Addcó thể giúp ích

    public static T[] Add<T>(T[] array, T item)
    {
        T[] returnarray = new T[array.Length + 1];
        for (int i = 0; i < array.Length; i++)
        {
            returnarray[i] = array[i];
        }
        returnarray[array.Length] = item;
        return returnarray;
    }

4

Tất cả các câu trả lời được đề xuất thực hiện giống như những gì họ nói họ muốn tránh, tạo một mảng mới và thêm một mục mới trong đó chỉ với việc mất thêm chi phí. LINQ không phải là phép thuật, danh sách T là một mảng có không gian bộ đệm có thêm một số không gian để tránh thay đổi kích thước mảng bên trong khi các mục được thêm vào.

Tất cả các khái niệm trừu tượng phải giải quyết cùng một vấn đề, tạo một mảng không có các ô trống chứa tất cả các giá trị và trả về chúng.

Nếu bạn cần sự linh hoạt, bạn có thể tạo một danh sách đủ lớn để bạn có thể sử dụng để vượt qua, sau đó làm điều đó. khác sử dụng một mảng và chia sẻ đối tượng an toàn luồng. Ngoài ra, Span mới giúp chia sẻ dữ liệu mà không phải sao chép danh sách xung quanh.

Để trả lời câu hỏi:

Array.Resize(ref myArray, myArray.Length + 1);
data[myArray.Length - 1] = Value;

4

Vì vậy, nếu bạn có một mảng hiện có, sửa chữa nhanh của tôi sẽ là

var tempList = originalArray.ToList();
tempList.Add(newitem);

Bây giờ chỉ cần thay thế mảng ban đầu bằng mảng mới

originalArray = tempList.ToArray();

Đã giải quyết giải pháp của tôi
praguan

3

Một Append<TSource>phương thức mới đã được thêm vàoIEnumerable<TSource> kể từ .NET Framework 4.7.1 và .NET Core 1.0.

Đây là cách sử dụng nó:

var numbers = new [] { "one", "two", "three" };
numbers = numbers.Append("four").ToArray();
Console.WriteLine(string.Join(", ", numbers)); // one, two, three, four

Lưu ý rằng nếu bạn muốn thêm phần tử vào đầu mảng, bạn có thể sử dụng Prepend<TSource>phương thức mới thay thế.


2

Sử dụng một danh sách sẽ là lựa chọn tốt nhất của bạn để quản lý bộ nhớ.


2

Điều gì về việc sử dụng một phương pháp mở rộng? Ví dụ:

public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> source, TSource item)
{
    return source.Union(new TSource[] { item });
}

ví dụ:

string[] sourceArray = new []
{
    "foo",
    "bar"
}
string additionalItem = "foobar";
string result = sourceArray.Union(additionalItem);

Lưu ý điều này bắt chước hành vi này của tiện ích mở rộng Uniion của Linq (được sử dụng để kết hợp hai mảng thành một mảng mới) và yêu cầu thư viện Linq hoạt động.


1

Tôi đồng ý với Ed. C # không làm điều này dễ dàng như cách VB làm với ReDim Preserve. Nếu không có bộ sưu tập, bạn sẽ phải sao chép mảng thành một bộ lớn hơn.


2
Cảm ơn Chúa! ReDim cực kỳ chậm khi bị lạm dụng. =)
Ed S.

ReDim Preservechỉ cần sao chép mảng thành một lager. Không có thay đổi kích thước mảng kỳ diệu.
Olivier Jacot-Descombes

1
string str = "string ";
List<string> li_str = new List<string>();
    for (int k = 0; k < 100; i++ )
         li_str.Add(str+k.ToString());
string[] arr_str = li_str.ToArray();

0
private static string[] GetMergedArray(string[] originalArray, string[] newArray)
    {
        int startIndexForNewArray = originalArray.Length;
        Array.Resize<string>(ref originalArray, originalArray.Length + newArray.Length);
        newArray.CopyTo(originalArray, startIndexForNewArray);
        return originalArray;
    }


0

Thật không may, sử dụng một danh sách sẽ không hoạt động trong mọi tình huống. Một danh sách và một mảng thực sự khác nhau và không thể hoán đổi cho nhau 100%. Nó sẽ phụ thuộc vào hoàn cảnh nếu đây sẽ là một công việc chấp nhận được xung quanh.


0

Vì câu hỏi này không hài lòng với câu trả lời được cung cấp, tôi muốn thêm câu trả lời này :)

public class CustomArrayList<T> 
 {  
   private T[] arr;  private int count;  

public int Count  
  {   
    get   
      {    
        return this.count;   
      }  
   }  
 private const int INITIAL_CAPACITY = 4;  

 public CustomArrayList(int capacity = INITIAL_CAPACITY) 
 {  
    this.arr = new T[capacity];   this.count = 0; 
  } 

 public void Add(T item) 
  {  
    GrowIfArrIsFull();  
   this.arr[this.count] = item;  this.count++; 
  }  

public void Insert(int index, T item) 
{  
 if (index > this.count || index < 0)  
    {   
      throw new IndexOutOfRangeException(    "Invalid index: " + index);  
     }  
     GrowIfArrIsFull();  
     Array.Copy(this.arr, index,   this.arr, index + 1, this.count - index);          
    this.arr[index] = item;  this.count++; }  

    private void GrowIfArrIsFull() 
    {  
    if (this.count + 1 > this.arr.Length)  
    {   
      T[] extendedArr = new T[this.arr.Length * 2];  
      Array.Copy(this.arr, extendedArr, this.count);  
      this.arr = extendedArr;  
    } 
  }
 }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.