c # .net의 기존 배열에 새 항목 추가


134

C # .net의 기존 문자열 배열에 새 항목을 추가하는 방법은 무엇입니까?

기존 데이터를 보존해야합니다.

답변:


121

동적 크기의 배열이 필요한 경우 List를 사용합니다.

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

27
필요한 경우 마지막에 ls.ToArray ()를 수행하십시오
Narayana

2
질문에서 요구 한 것과 다른 기계공을 사용하는 것은 답이 아닙니다.
user11909

@ user2190035 : 그 아이디어를 어디에서 얻었는지 확실하지 않으며, 찬성 한 111 명이 귀하와 동의하지 않을 것입니다. 배열을 확장하는 더 좋은 방법을 알고 있다면 반드시 게시하십시오. 나는 당신의 재배치와 수동 사본이 목록을 사용하는 것보다 낫다는 것을 의심합니다. 때때로 대답은 "하지 마십시오"입니다.
Ed S.

@EdS. 질문은 기존 문자열 배열에 항목을 추가하는 방법 이지만이 답변에는 배열이 전혀 없으며 대신 List <>를 만듭니다 . 내 응용 프로그램에서 유형을 List <>로 변경할 수 없으므로 배열 크기를 조정해야합니다 (복사본 만들기). Ali Ersöz의 답변이 도움이되었습니다.
user11909

@ user2190035 : IEnumerable <T> .ToArray (). 나는 매일 C #을 작성하고 그런 배열의 크기를 조정할 필요가 없었습니다.
Ed S.

100

그것은 해결책이 될 수 있습니다.

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

그러나 동적 크기 배열의 경우 목록도 선호합니다.


@Konrad, 배열의 데이터를 반드시 보존합니다.
Ali Ersöz

1
이것은 몇 번 이상 호출하는 데 적합하지 않습니다. '크기 조정'기능이 큰 성능을 발휘하기 때문입니다. 한두 번 버그, 이것은 매우 좋습니다.
광고

53

LINQ 사용 :

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

나는 이것을 하나의 라이너로 사용하는 것을 좋아하며 switch 문, 간단한 if 문에 포함하거나 인수로 전달하는 것이 매우 편리합니다.

편집하다:

일부 사람들은 new[] { newitem }작은 한 항목의 임시 배열을 만들기 때문에 싫어 합니다. 다음은 Enumerable.Repeat객체를 만들 필요가없는 버전을 사용 하는 것입니다 (적어도 표면에는 없습니다. .NET 반복자는 아마도 테이블 아래에 많은 상태 머신 객체를 만들 것입니다).

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

그리고 배열이 null시작 되지 않는 것이 확실하다면 다음과 같이 단순화 할 수 있습니다.

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

정렬 된 컬렉션에 항목을 추가 List하려면 배열이 아닌 원하는 데이터 구조 일 것입니다.


1
아주 좋은 +1. 일반 확장 방법과 비슷한 코드가 있습니다. 이 답변에 코드를 포함 시켰습니다 : stackoverflow.com/a/11035286/673545
dblood

이것은 "C #에서 한 줄의 코드로 배열에 추가하는 방법"을 검색하는 동안 매우 유용하다는 사실을 발견했습니다.
gary

28

아주 오래된 질문이지만 여전히 이것을 추가하고 싶었습니다.

하나의 라이너를 찾고 있다면 아래 코드를 사용할 수 있습니다. 열거 형과 "신규"(질문이 제기 된 이후) 이니셜 라이저 구문을 허용하는 목록 생성자를 결합합니다.

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

27

C #에서 배열은 불변 예를 들어 string[], int[]. 즉, 크기를 조정할 수 없습니다. 완전히 새로운 배열을 만들어야합니다.

다음은 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;
    }
}

보시다시피 새로운 크기의 새 배열을 만들고 소스 배열의 내용을 복사하고 참조를 새 배열로 설정합니다. 이에 대한 힌트 는 첫 번째 매개 변수 의 ref 키워드입니다.

새 항목에 새 슬롯동적으로 할당 할 수있는 목록이 있습니다 . 예를 들어 List <T> 입니다. 이것들은 불변 배열을 포함하고 필요할 때 크기를 조정합니다 (List <T>는 연결된 목록 구현이 아닙니다!). ArrayList 는 Generics가없는 것과 동일합니다 ( Object 배열 사용).

LinkedList <T> 는 실제 연결 목록 구현입니다. 불행히도 LinkListNode <T> 요소 만 목록에 추가 할 수 있으므로 고유 한 목록 요소를이 노드 유형으로 랩핑해야합니다. 나는 그것의 사용이 드물다고 생각합니다.


난 당신이 Array.Copy 의미가 생각
user123456

2
불가능한 이유에 대한 정보 만 제공하고 목록 사용을 제안하지 않는 유일한 대답은 다음과 같습니다.
Gilad Green

Aray.Resize내용을 잃지 않고 배열의 크기를 조정할 수 있다고 생각 합니다. docs.microsoft.com/ko-kr/dotnet/api/…
AbdelAziz AbdelLatef 14

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

7

@Stephen Chung이 제공하는 답변을 LINQ 기반 논리를 사용하여 일반 유형을 사용하여 확장 방법을 만들 수 있습니다.

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();
    }

}

그런 다음 이와 같이 배열에서 직접 호출 할 수 있습니다.

    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...
    }

명백히, AddRangeToArray () 메소드는 Concat ()과 동일한 기능을 가지고 있기 때문에 약간 과잉 인 것처럼 보이지만, 이렇게하면 최종 코드가 이것과 반대로 배열에서 직접 "작동"할 수 있습니다.

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

감사합니다. 매우 도움이되었으므로 항목을 제거 할 수있는 옵션을 추가했습니다.
Tal Segal

@TalSegal 천만에요, 내 기쁨. 적합하다고 생각되는 코드를 사용하십시오!
dblood 2013 년

6

배열을 변경 불가능하고 고정 된 크기로 유지하는 것이 좋습니다.

당신이 시뮬레이션 할 수 AddExtension MethodIEnumerable.Concat()

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

5

배열로 많은 작업을하고 어떤 이유로 목록을 작성하지 않으면이 일반 유형의 반환 일반 메소드 Add가 도움이 될 수 있습니다

    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

제안 된 모든 답변은 회피하려는 말과 동일하게 수행하여 새로운 배열을 만들고 더 많은 오버 헤드를 잃은 채로 새로운 항목을 추가합니다. LINQ는 마술이 아닙니다. T 목록은 항목이 추가 될 때 내부 배열의 크기를 조정하지 않도록 여분의 공간이있는 버퍼 공간이있는 배열입니다.

모든 추상화는 동일한 문제를 해결하고 모든 값을 보유하는 빈 슬롯이없는 배열을 생성하여 반환해야합니다.

융통성이 필요한 경우 통과 할 수있는 충분한 목록을 만들 수 있습니다. 그렇지 않으면 배열을 사용하고 해당 스레드 안전 객체를 공유하십시오. 또한 새로운 스팬은 목록을 복사하지 않고도 데이터를 공유 할 수 있습니다.

질문에 대답하려면 :

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

4

따라서 기존 배열이 있으면 빠른 해결 방법은

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

이제 원래 배열을 새 배열로 교체하십시오.

originalArray = tempList.ToArray();

내 솔루션을 해결
praguan

3

새로운 Append<TSource>방법이 추가되었습니다IEnumerable<TSource>.NET Framework 4.7.1 및 .NET Core 1.0 이후 .

사용 방법은 다음과 같습니다.

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

배열의 시작 부분에 요소를 추가하려는 경우 Prepend<TSource>대신 새 메소드를 사용할 수 있습니다 .


2

메모리 관리를 위해서는 목록을 사용하는 것이 가장 좋습니다.


2

확장 방법을 사용하는 것은 어떻습니까? 예를 들어 :

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

예를 들어 :

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

이것은 Linq의 Uniion 확장 기능 (두 배열을 새로운 배열로 결합하는 데 사용됨)의 동작을 모방하며 Linq 라이브러리가 작동해야한다는 점에 유의하십시오.


1

Ed에 동의합니다. C #은 VD가 ReDim Preserve를 사용하는 방식을 쉽게 만들지 않습니다. 컬렉션이 없으면 배열을 더 큰 배열로 복사해야합니다.


2
하나님 감사합니다! ReDim은 남용 될 때 엄청나게 느립니다. =)
Ed S.

ReDim Preserve단순히 배열을 더 큰 배열로 복사합니다. 기적적인 배열 크기 조정이 없습니다.
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

불행히도 목록을 사용하는 것이 모든 상황에서 작동하지는 않습니다. 목록과 배열은 실제로 다르며 100 % 호환되지 않습니다. 이것이 적절한 해결책이라면 상황에 따라 달라질 것입니다.


0

이 질문에 제공된 답변이 만족스럽지 않으므로이 답변을 추가하고 싶습니다. :)

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;  
    } 
  }
 }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.