code

두 배열을 에서 병합하는 중입니다.그물

starcafe 2023. 5. 3. 21:36
반응형

두 배열을 에서 병합하는 중입니다.그물

에 내장 기능이 있습니까?두 개의 어레이를 사용하여 하나의 어레이로 병합하는 NET 2.0?

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

저는 가능하다면 이것을 달성하기 위해 제 기능을 쓰는 것을 피하고 싶습니다.

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에서는 어레이 외에 직접적인 방법이 없습니다.복사가 가장 좋은 해결책일 것입니다.

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.

LINQ 사용:

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

중복 항목이 제거됩니다.중복 항목을 보관하려면 Concat을 사용합니다.

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

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에서 사용 가능한 배열 방법에 대한 자세한 정보.

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

LINQ 사용:

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

먼저, "여기서 어레이를 정말 사용해야 합니까?"라는 질문을 스스로에게 던져야 합니다.

속도가 가장 중요한 것을 만드는 것이 아니라면, 다음과 같은 입력된 목록.List<int>그게 아마도 가야 할 길일 겁니다.네트워크를 통해 데이터를 전송할 때 바이트 배열을 사용하는 경우가 유일합니다.그 외에는 절대 만지지 않습니다.

LINQ를 사용하는 것이 더 쉽습니다.

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

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

Array를 사용하시면 될 것 같습니다.알겠습니다.원본 인덱스와 대상 인덱스를 사용하므로 한 배열을 다른 배열에 추가할 수 있습니다.하나를 다른 하나에 추가하는 것보다 더 복잡한 작업을 수행해야 하는 경우에는 이 도구가 적합하지 않을 수 있습니다.

모두가 이미 발언권을 가지고 있지만, "확장 방법으로 사용"하는 접근 방식보다 더 읽기 쉬운 방법이라고 생각합니다.

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

그러나 2개의 어레이를 함께 사용할 때만 사용할 수 있습니다.

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

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 }

대상 어레이에 충분한 공간이 있다고 가정하면 이 작동합니다.사용해 볼 수도 있습니다.List<T>및 그 방법.

개인적으로, 저는 빠른 프로토타이핑을 위해 마음대로 추가하거나 제거하는 저만의 언어 확장을 선호합니다.

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

//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 을 참조하십시오.

참고: 확장되지 않은 IEnumberable 개체를 반환합니다.확장 개체를 반환하는 것이 조금 느립니다.

저는 2002년부터 코드 프로젝트와 '스택 오버플로'에 도움이 되는 사람들에게 많은 크레딧을 제공하면서 이러한 확장을 컴파일했습니다.잠시 후에 이것들을 공개하고 여기에 링크를 올리겠습니다.

옵션으로 사용 중인 어레이가 Boolean(boolean), Char, SByte, Byte, Int16(short), UInt16, Int32(int), UInt32, Int64(long), UInttr, UIntPtr, Single 또는 Double 등의 원시 유형인 경우 버퍼를 사용해 볼 수 있습니다.복사 차단.버퍼 클래스의 MSDN 페이지에 따라:

이 클래스는 시스템의 유사한 메서드보다 원시 형식을 조작하는 데 더 나은 성능을 제공합니다.배열 클래스입니다.

@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);

사이의 구문에는 거의 차이가 없습니다.Buffer.BlockCopy그리고Array.Copy@OwenP가 사용했지만, 이것은 (조금이라도) 더 빠를 것입니다.

알 수 없는 수의 어레이를 결합할 수 있는 솔루션이 필요했습니다.

다른 누구도 다음을 사용하여 솔루션을 제공하지 않았다는 사실에 놀랐습니다.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);

참고: 구별하여 사용할 경우에는 반드시 주문을 보장하지 않습니다.

다른 사용자가 두 이미지 바이트 배열을 병합하는 방법을 찾는 경우:

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

어레이 자체에 소스 어레이가 있는 경우 여러 개 선택:

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

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

다음은 배열을 사용하는 간단한 예입니다.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);

당신은 그것을 더 쉽게 이해할 수 없을 것 같습니다.

기본 제공되는 어레이 유형이 아닌 고유한 어레이 유형을 사용하는 것으로 가정합니다.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#입니다.

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 + " ");  

위의 코드를 사용하면 두 어레이를 쉽게 병합할 수 있습니다.

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;
    }
}
string[] names1 = new string[] { "Ava", "Emma", "Olivia" };
string[] names2 = new string[] { "Olivia", "Sophia", "Emma" };
List<string> arr = new List<string>(names1.Length + names2.Length);
arr.AddRange(names1);
arr.AddRange(names2);
string[] result = arr.Distinct().ToArray();
foreach(string str in result)
{
    Console.WriteLine(str.ToString());
}

Console.ReadLine();

저는 어레이 자체를 넘어서는 라이브러리나 기능을 사용하지 않고 접근 방식을 찾고 싶었습니다.

처음 두 가지 예는 대부분 처음부터 논리를 읽기 위한 것이지만, 상황에 따라 성능에 차이가 있을 수 있는지도 궁금합니다.

세 번째 예는 가장 실용적인 선택입니다.

// Two for-loops
private static int[] MergedArrays_1(int[] a, int[] b)
{
    int[] result = new int[a.Length + b.Length];
    for (int i = 0; i < a.Length; i++)
    {
        result[i] = a[i];
    }
    for (int i = a.Length; i < result.Length; i++)
    {
        result[i] = b[i - a.Length];
    }
    return result;
}

// One for-loop
private static int[] MergedArrays_2(int[] a, int[] b)
{
    int[] results = new int[a.Length + b.Length];
    for (int i = 0; i < results.Length; i++)
    {
        results[i] = (i < a.Length) ? a[i] : b[i - a.Length];
    }
    return results;
}

// Array Method
private static int[] MergedArrays_3(int[] a, int[] b)
{
    int[] results = new int[a.Length + b.Length];
    a.CopyTo(results, 0);
    b.CopyTo(results, a.Length);
    return results;
}

마지막으로, 저는 params 키워드를 사용하여 여러 어레이를 병합할 수 있는 네 번째 예를 만들었습니다.

int[] result = MultipleMergedArrays(arrayOne, arrayTwo, arrayThree);
private static int[] MultipleMergedArrays(params int[][] a)
{
    // Get Length
    int resultsLength = 0;
    for (int row = 0; row < a.GetLength(0); row++)
    {
        resultsLength += a.Length;
    }

    // Initialize
    int[] results = new int[resultsLength];

    // Add Items
    int index = 0;
    for (int row = 0; row < a.GetLength(0); row++)
    {
        a[row].CopyTo(results, index);
        index += a[row].Length;
    }
    return results;
}

매개 변수를 사용할 때 작동하는 방식은 1차원 배열이 들쭉날쭉한 배열로 전달되는 것입니다.

GetLength(0)는 jagged 배열에 포함된 배열 수를 반환합니다.

코드는 먼저 모든 배열의 길이를 계산한 다음 해당 크기를 기준으로 새 배열을 초기화하고 CopyTo() 메서드를 사용하여 새 결과 배열에 전체 배열을 추가하기 시작하는 동시에 추가된 각 배열의 길이를 인덱스 카운터에 추가합니다.

PS: 병합할 때 배열에서 빈 항목 또는 특정 항목을 제거해야 하는 경우가 있습니다.

private static int[] RemoveEmpty(int[] array)
{
    int count = 0;
    for (int i = 0; i < array.Length; i++)
    {
        if (array[i] == 0) count++;
    }

    int[] result = new int[array.Length - count];

    count = 0;
    for (int i = 0; i < array.Length; i++)
    {
        if (array[i] == 0) continue;
        result[count] = array[i];
        count++;
    }

    return result;
}

이 기능은 위의 기능과 결합할 수 있습니다.

배열을 사용하여 0과 일치하는 항목의 수를 계산합니다.적절한 크기의 새 배열을 만듭니다.그런 다음 카운터가 재활용되어 입력 배열의 값을 새 결과 배열과 더 작은 결과 배열에 배치할 위치에 대한 색인으로 사용됩니다.항목이 0과 일치하면 해당 루프의 나머지 코드를 건너뛰고 정수 카운터를 늘리지 않고 다음 라운드로 계속됩니다.

.NET 5 이후로, 우리는 이제 할당이 있습니다.제안된 솔루션에 대해 성능을 추가(소규모) 향상시킬 수 있는 Unitialized Array:

public static T[] ConcatArrays<T>(IEnumerable<T[]> arrays)
{
    var result = GC.AllocateUnitializedArray<T>(arrays.Sum(a => a.Length));
    var offset = 0;
    foreach (var a in arrays)
    {
        a.CopyTo(result, offset);
        offset += a.Length;
    }
    return result;
}

효율적인 솔루션을 위해 다음을 시도할 수 있습니다.

        //
    ///<summary>Join two arrays together. At least one array must exist.</summary>
    public static T[] Append<T>( this T[] a1, T[] a2 ) {
        if ( null == a1 && null == a2 ) return null;
        int l1 = 0;
        if ( null != a1 ) l1 = a1.Length;
        int l2 = 0;
        if ( null != a2 ) l2 = a2.Length;
        var b = new T[ l1 + l2 ];
        if ( null != a1 ) Array.Copy( a1, b, l1 );
        if ( null != a2 ) Array.Copy( a2, 0, b, l1, l2 );
        return b;
    }

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

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--];
    }
}

여러 어레이를 결합하는 간단한 코드:

string[] arr1 = ...
string[] arr2 = ...
string[] arr3 = ...    
List<string> arr = new List<string>(arr1.Length + arr2.Length + arr3.Length);
arr.AddRange(arr1);
arr.AddRange(arr2);
arr.AddRange(arr3);
string[] result = arr.ToArray();

이것은 이것을 하는 또 다른 방법입니다 :)

public static void ArrayPush<T>(ref T[] table, object value)
{
    Array.Resize(ref table, table.Length + 1); // Resizing the array for the cloned length (+-) (+1)
    table.SetValue(value, table.Length - 1); // Setting the value for the new element
}

public static void MergeArrays<T>(ref T[] tableOne, T[] tableTwo) {
    foreach(var element in tableTwo) {
        ArrayPush(ref tableOne, element);
    }
}

다음은 스니펫/예시입니다.

사용해 보십시오.

ArrayLIst al = new ArrayList();
al.AddRange(array_1);
al.AddRange(array_2);
al.AddRange(array_3);
array_4 = al.ToArray();

언급URL : https://stackoverflow.com/questions/59217/merging-two-arrays-in-net

반응형