.NET에서 두 배열 병합


225

.NET 2.0에는 두 개의 배열을 가져 와서 하나의 배열로 병합하는 기본 제공 기능이 있습니까?

배열은 모두 같은 유형입니다. 코드 배열 내에서 널리 사용되는 함수에서 이러한 배열을 가져오고 데이터를 다른 형식으로 반환하도록 함수를 수정할 수 없습니다.

가능한 경우 이것을 달성하기 위해 내 자신의 함수를 작성하지 않으려 고합니다.

답변:


118

배열 중 하나를 조작 할 수 있으면 복사를 수행하기 전에 크기를 조정할 수 있습니다.

T[] array1 = getOneArray();
T[] array2 = getAnotherArray();
int array1OriginalLength = array1.Length;
Array.Resize<T>(ref array1, array1OriginalLength + array2.Length);
Array.Copy(array2, 0, array1, array1OriginalLength, array2.Length);

그렇지 않으면 새로운 배열을 만들 수 있습니다

T[] array1 = getOneArray();
T[] array2 = getAnotherArray();
T[] newArray = new T[array1.Length + array2.Length];
Array.Copy(array1, newArray, array1.Length);
Array.Copy(array2, 0, newArray, array1.Length, array2.Length);

MSDN 볼 수 배열 방법에 대한 자세한 .


1
.NET 4.0은 어떤가요?
Shimmy Weitzhandler

4
참고 Array.Resize실제로 배열, 그것은을 복사 크기를 조정하지 않습니다. 그렇기 때문에 첫 번째 매개 변수는 참조가 아닙니다 (첫 번째 코드는 컴파일되지 않을 것입니다).
코드 InChaos

2
첫 번째 코드 조각을 버릴 것입니다. 이점이 없으며 IMO를 읽기가 더 어렵습니다.
코드 InChaos

3
Array.Copy의 두 번째 코드 예제에서 매개 변수의 순서가 잘못되었습니다. Array.Copy (array1, newArray, 0)를 사용하십시오. 대신에.
marco birchler

당신은 또한 할 수 있습니다 .. List <byte> finalArray = new List <byte> (); finalArray.AddRange (array1); finalArray.AddRange (array2); ==> finalArray.toArray ();
Cédric Boivin

448

C # 3.0에서는 LINQ의 Concat 방법을 사용하여이를 쉽게 수행 할 수 있습니다.

int[] front = { 1, 2, 3, 4 };
int[] back = { 5, 6, 7, 8 };
int[] combined = front.Concat(back).ToArray();

C # 2.0에서는 그러한 직접적인 방법이 없지만 Array.Copy가 가장 좋은 솔루션 일 것입니다.

int[] front = { 1, 2, 3, 4 };
int[] back = { 5, 6, 7, 8 };

int[] combined = new int[front.Length + back.Length];
Array.Copy(front, combined, front.Length);
Array.Copy(back, 0, combined, front.Length, back.Length);

이것은 자신의 버전을 쉽게 구현하는 데 사용할 수 있습니다 Concat.


1
나는 그 LINQ 구현을 좋아한다. 나는 정말로 점프하고 LINQ에 곧 도착할 필요가있다. ..
GEOCHET

1
LINQ 구현의 가장 중요한 부분은 간결 할뿐만 아니라 IEnumerable에 대해 작동하기 때문에 2.0 버전만큼 효율적입니다.
브래드 윌슨

이 답변에는 이러한 방법이 포함되어 있으며 벤치마킹 결과도 제공합니다. stackoverflow.com/questions/415291/…
Demir

이것은 아마도 가장 쉬운 방법이지만 Concat은 foreach 루프 + 수율 (참조 소스 참조)을 사용하여 구현되므로 큰 배열에서는 효율적이지 않습니다. BlockCopy 솔루션이 더 빠릅니다.
tigrou

1
결합 된 결과 만 반복하려면 배열로 변환 할 필요가 없습니다. 이 마지막 작업은 배열 복사를 수행합니다. IEnumerable <int>를 반복하면 그렇게 할 필요가 없습니다. 물론 배열이 필요한 이유가있을 수 있습니다.
조나

82

LINQ 사용 :

var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = arr1.Union(arr2).ToArray();

중복이 제거됩니다. 중복을 유지하려면 Concat을 사용하십시오.


132
주의 : Union은 중복을 제거합니다.
Yogee

1
@Yogee, SQL에서와 마찬가지로 기억하기 쉽고 명명법은 집합 이론과 관련이 있습니다.
Zbigniew Wiadro

8
중복을 제거하므로 올바른 답변이 될 수 없습니다.
Roni Tovi 2016 년

1
나는 Simon이 이미 Union 문제와 그가 제안한 대체 접근법을 언급 한 것을 본다. Simon이 자신이 무엇을 응답하는지 알기 때문에 이에 대해 더 논의 할 필요가 없습니다.
Sudhakar Chavali

41

중복을 제거하지 않으려면 다음을 시도하십시오.

LINQ 사용 :

var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = arr1.Concat(arr2).ToArray();

11

먼저 "여기에서 실제로 배열을 사용해야합니까?"라는 질문을 스스로 확인하십시오.

속도가 가장 중요한 곳에 무언가를 만들지 않는 한, 형식화 된 목록 List<int>은 아마도 갈 길입니다. 내가 배열을 사용하는 유일한 시간은 네트워크를 통해 물건을 보낼 때 바이트 배열입니다. 그 외에는 절대 만지지 않습니다.


큰 +1입니다. 모범 사례는 List<T>퍼블릭 API 노출을 피하는 것입니다 . blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx
TrueWill

10

LINQ를 사용하는 것이 더 쉬울 것입니다 .

var array = new string[] { "test" }.ToList();
var array1 = new string[] { "test" }.ToList();
array.AddRange(array1);
var result = array.ToArray();

먼저 배열을 목록으로 변환하고 병합하십시오 ... 그런 다음 목록을 배열로 다시 변환하십시오. :)


배열을 직접 사용하지 않습니다. 당신은 목록을 사용했습니다!
Behzad Ebrahimi

7

Array.Copy 를 사용할 수 있다고 생각합니다 . 소스 인덱스와 대상 인덱스가 필요하므로 한 배열을 다른 배열에 추가 할 수 있습니다. 단순히 다른 것을 추가하는 것보다 더 복잡해 져야하는 경우에는 이것이 올바른 도구가 아닐 수도 있습니다.



4

개인적으로, 나는 빠른 시제품 제작을 위해 마음대로 추가하거나 제거하는 내 자신의 언어 확장을 선호합니다.

다음은 문자열의 예입니다.

//resides in IEnumerableStringExtensions.cs
public static class IEnumerableStringExtensions
{
   public static IEnumerable<string> Append(this string[] arrayInitial, string[] arrayToAppend)
   {
       string[] ret = new string[arrayInitial.Length + arrayToAppend.Length];
       arrayInitial.CopyTo(ret, 0);
       arrayToAppend.CopyTo(ret, arrayInitial.Length);

       return ret;
   }
}

LINQ 및 Concat보다 훨씬 빠릅니다. 더 빨리, IEnumerable전달 된 배열의 참조 / 포인터를 저장하고 일반 배열 인 것처럼 전체 컬렉션을 반복 할 수 있는 사용자 지정 유형 래퍼를 사용하고 있습니다. (HPC, 그래픽 처리, 그래픽 렌더링에 유용합니다 ...)

귀하의 코드 :

var someStringArray = new[]{"a", "b", "c"};
var someStringArray2 = new[]{"d", "e", "f"};
someStringArray.Append(someStringArray2 ); //contains a,b,c,d,e,f

전체 코드 및 제네릭 버전은 https://gist.github.com/lsauer/7919764를 참조하십시오.

참고 : 확장되지 않은 IEnumerable 개체를 반환합니다. 확장 객체를 반환하는 것은 약간 느립니다.

나는 2002 년부터 그러한 확장을 컴파일했으며 CodeProject 및 'Stackoverflow'에 도움이되는 사람들에게 많은 크레딧을 제공했습니다. 나는 이것을 곧 풀어서 여기에 링크를 넣을 것이다.


4

모든 사람들은 이미 자신의 의견을 가지고 있지만 "확장 방법으로 사용"접근 방식보다 더 읽기 쉽다고 생각합니다.

var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = Queryable.Concat(arr1, arr2).ToArray();

그러나 2 개의 배열을 결합 할 때만 사용할 수 있습니다.


4

이것이 내가 생각해 낸 것입니다. 가변 배열 수에 대해 작동합니다.

public static T[] ConcatArrays<T>(params T[][] args)
    {
        if (args == null)
            throw new ArgumentNullException();

        var offset = 0;
        var newLength = args.Sum(arr => arr.Length); 
        var newArray = new T[newLength];

        foreach (var arr in args)
        {
            Buffer.BlockCopy(arr, 0, newArray, offset, arr.Length);
            offset += arr.Length;
        }

        return newArray;
    }

...

var header = new byte[] { 0, 1, 2};
var data = new byte[] { 3, 4, 5, 6 };
var checksum = new byte[] {7, 0};
var newArray = ConcatArrays(header, data, checksum);
//output byte[9] { 0, 1, 2, 3, 4, 5, 6, 7, 0 }

3

옵션으로 언급하자면 : 작업중 인 배열이 기본 유형 인 경우-부울 (bool), Char, SByte, Byte, Int16 (short), UInt16, Int32 (int), UInt32, Int64 (long ), UInt64, IntPtr, UIntPtr, Single 또는 Double – Buffer.BlockCopy를 사용해 볼 수 있습니다 . 버퍼 클래스 의 MSDN 페이지에 따르면 :

이 클래스는 System.Array 클래스의 유사한 메소드보다 기본 유형을 조작하는 데 더 나은 성능을 제공합니다 .

@OwenP의 답변 에서 C # 2.0 예제를 시작점으로 사용하면 다음과 같이 작동합니다.

int[] front = { 1, 2, 3, 4 };
int[] back = { 5, 6, 7, 8 };

int[] combined = new int[front.Length + back.Length];
Buffer.BlockCopy(front, 0, combined, 0, front.Length);
Buffer.BlockCopy(back, 0, combined, front.Length, back.Length);

@OwenP Buffer.BlockCopy와 구문의 차이는 거의 Array.Copy없지만 조금 더 빠르더라도 빠릅니다.


2

다른 사람이 두 개의 이미지 바이트 배열을 병합하는 방법을 찾고있는 경우 :

        private void LoadImage()
        {
            string src = string.empty;
            byte[] mergedImageData = new byte[0];

            mergedImageData = MergeTwoImageByteArrays(watermarkByteArray, backgroundImageByteArray);
            src = "data:image/png;base64," + Convert.ToBase64String(mergedImageData);
            MyImage.ImageUrl = src;
        }

        private byte[] MergeTwoImageByteArrays(byte[] imageBytes, byte[] imageBaseBytes)
        {
            byte[] mergedImageData = new byte[0];
            using (var msBase = new MemoryStream(imageBaseBytes))
            {
                System.Drawing.Image imgBase = System.Drawing.Image.FromStream(msBase);
                Graphics gBase = Graphics.FromImage(imgBase);
                using (var msInfo = new MemoryStream(imageBytes))
                {
                    System.Drawing.Image imgInfo = System.Drawing.Image.FromStream(msInfo);
                    Graphics gInfo = Graphics.FromImage(imgInfo);
                    gBase.DrawImage(imgInfo, new Point(0, 0));
                    //imgBase.Save(Server.MapPath("_____testImg.png"), ImageFormat.Png);
                    MemoryStream mergedImageStream = new MemoryStream();
                    imgBase.Save(mergedImageStream, ImageFormat.Png);
                    mergedImageData = mergedImageStream.ToArray();
                    mergedImageStream.Close();
                }
            }
            return mergedImageData;
        }

1

다음은 Array.CopyTo를 사용하는 간단한 예입니다. 나는 그것이 당신의 질문에 대답하고 CopyTo 사용법의 예를 제공한다고 생각합니다. 도움이 약간 불분명하기 때문에이 기능을 사용해야 할 때 항상 당황합니다. 색인은 삽입이 발생하는 대상 배열의 위치입니다.

int[] xSrc1 = new int[3] { 0, 1, 2 };
int[] xSrc2 = new int[5] { 3, 4, 5, 6 , 7 };

int[] xAll = new int[xSrc1.Length + xSrc2.Length];
xSrc1.CopyTo(xAll, 0);
xSrc2.CopyTo(xAll, xSrc1.Length);

나는 당신이 그것을 더 간단하게 얻을 수 없다고 생각합니다.


1

알 수없는 배열을 결합하는 솔루션이 필요했습니다.

아무도 SelectMany와 함께 사용하는 솔루션을 제공하지 않았습니다 params.

 private static T[] Combine<T>(params IEnumerable<T>[] items) =>
                    items.SelectMany(i => i).Distinct().ToArray();

별개의 항목을 원하지 않으면 별개의 항목을 제거하십시오.

 public string[] Reds = new [] { "Red", "Crimson", "TrafficLightRed" };
 public string[] Greens = new [] { "Green", "LimeGreen" };
 public string[] Blues = new [] { "Blue", "SkyBlue", "Navy" };

 public string[] Colors = Combine(Reds, Greens, Blues);

참고 : distinct를 사용할 때 순서를 보장 할 수는 없습니다.


0

내장 .NET 배열과 달리 자체 배열 유형을 사용한다고 가정합니다.

public string[] merge(input1, input2)
{
    string[] output = new string[input1.length + input2.length];
    for(int i = 0; i < output.length; i++)
    {
        if (i >= input1.length)
            output[i] = input2[i-input1.length];
        else
            output[i] = input1[i];
    }
    return output;
}

이를 수행하는 또 다른 방법은 내장 ArrayList 클래스를 사용하는 것입니다.

public ArrayList merge(input1, input2)
{
    Arraylist output = new ArrayList();
    foreach(string val in input1)
        output.add(val);
    foreach(string val in input2)
        output.add(val);
    return output;
}

두 예제 모두 C #입니다.


0
int [] SouceArray1 = new int[] {2,1,3};
int [] SourceArray2 = new int[] {4,5,6};
int [] targetArray = new int [SouceArray1.Length + SourceArray2.Length];
SouceArray1.CopyTo(targetArray,0);
SourceArray2.CopyTo(targetArray,SouceArray1.Length) ; 
foreach (int i in targetArray) Console.WriteLine(i + " ");  

위의 코드를 사용하면 두 배열을 쉽게 병합 할 수 있습니다.


0

null 처리를위한 생성 및 확장 방법

public static class IEnumerableExtenions
{
    public static IEnumerable<T> UnionIfNotNull<T>(this IEnumerable<T> list1, IEnumerable<T> list2)
    {
        if (list1 != null && list2 != null)
            return list1.Union(list2);
        else if (list1 != null)
            return list1;
        else if (list2 != null)
            return list2;
        else return null;
    }
}

0

배열 자체에 소스 배열이있는 경우 SelectMany 를 사용할 수 있습니다 .

var arrays = new[]{new[]{1, 2, 3}, new[]{4, 5, 6}};
var combined = arrays.SelectMany(a => a).ToArray();
foreach (var v in combined) Console.WriteLine(v);   

준다

1
2
3
4
5
6

아마도 이것이 가장 빠른 방법은 아니지만 사용 사례에 따라 적합 할 수 있습니다.


-1

이 코드는 모든 경우에 적용됩니다.

int[] a1 ={3,4,5,6};
int[] a2 = {4,7,9};
int i = a1.Length-1;
int j = a2.Length-1;
int resultIndex=  i+j+1;
Array.Resize(ref a2, a1.Length +a2.Length);
while(resultIndex >=0)
{
    if(i != 0 && j !=0)
    {
        if(a1[i] > a2[j])
        {
            a2[resultIndex--] = a[i--];
        }
        else
        {
            a2[resultIndex--] = a[j--];
        }
    }
    else if(i>=0 && j<=0)
    { 
        a2[resultIndex--] = a[i--];
    }
    else if(j>=0 && i <=0)
    {
       a2[resultIndex--] = a[j--];
    }
}

제공하는 솔루션에 대한 추가 설명을 추가해 주시겠습니까?
abarisone

1
이 코드 스 니펫은 문제를 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 실제로 도움이됩니다. 앞으로 독자에게 질문에 대한 답변을 제공하고 있으며 해당 사람들이 코드 제안의 이유를 모를 수도 있습니다.
gunr2171

이것은 MergeSort 재귀 전략의 일부로 자체적으로 유용하지만 OP가 요청한 것 이상일 수있는 정렬 된 병합으로 보입니다.
Darrel Hoffman

이 솔루션은 효과가 있지만 C # 및 VB.Net이 소개 된 이후 많은 기술을 사용할 수 있으므로 사람들은 그러한 솔루션을 선호하지 않을 수 있습니다.
Sudhakar Chavali

-2

이 시도:

ArrayLIst al = new ArrayList();
al.AddRange(array_1);
al.AddRange(array_2);
al.AddRange(array_3);
array_4 = al.ToArray();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.