programing

C# 어레이를 단일 값으로 채우는/인스턴스하는 방법은 무엇입니까?

kakaobank 2023. 5. 22. 21:15
반응형

C# 어레이를 단일 값으로 채우는/인스턴스하는 방법은 무엇입니까?

C#에서 값 유형의 인스턴스화된 배열은 유형의 기본값(예: bool의 경우 false, int의 경우 0)으로 자동으로 채워집니다.

기본값이 아닌 시드 값으로 배열을 자동으로 채우는 방법이 있습니까?생성 시 또는 이후에 기본 제공되는 메서드(예: Java의 Arrays.fill()))?False 대신 기본적으로 True인 부울 배열을 원한다고 합니다.이를 위한 기본 제공 방법이 있습니까? 아니면 for 루프를 사용하여 어레이를 반복해야 합니까?

 // Example pseudo-code:
 bool[] abValues = new[1000000];
 Array.Populate(abValues, true);

 // Currently how I'm handling this:
 bool[] abValues = new[1000000];
 for (int i = 0; i < 1000000; i++)
 {
     abValues[i] = true;
 }

배열을 반복하고 각 값을 true로 "재설정"해야 하는 것은 비효율적입니다.이 근처에 뭔가 있나요?어쩌면 모든 가치관을 뒤집어서요?

이 질문을 입력하고 생각해 본 결과, 기본값은 단순히 C#이 배후에서 이러한 개체의 메모리 할당을 처리하는 방식의 결과라고 생각합니다. 따라서 이 작업은 불가능할 것으로 예상됩니다.하지만 저는 여전히 확실히 알고 싶습니다!

Enumerable.Repeat(true, 1000000).ToArray();

프레임워크 방법에 대해서는 잘 모르지만 빠른 도움말을 작성해 주시면 됩니다.

public static void Populate<T>(this T[] arr, T value ) {
  for ( int i = 0; i < arr.Length;i++ ) {
    arr[i] = value;
  }
}

,000개의 어레이로 새 true값:

var items = Enumerable.Repeat<bool>(true, 1000).ToArray();  // Or ToList(), etc.

마찬가지로 정수 시퀀스를 생성할 수 있습니다.

var items = Enumerable.Range(0, 1000).ToArray();  // 0..999

.NET Core 2.0+ 및 .NET Standard 2.1+에서 사용할 수 있습니다.

크기가 가변적인 대규모 어레이의 경우 다음을 사용해야 합니다.

Enumerable.Repeat(true, 1000000).ToArray();

작은 배열의 경우 C# 3의 컬렉션 초기화 구문을 사용할 수 있습니다.

bool[] vals = new bool[]{ false, false, false, false, false, false, false };

컬렉션 초기화 구문의 이점은 각 슬롯에서 동일한 값을 사용할 필요가 없고 식이나 함수를 사용하여 슬롯을 초기화할 수 있다는 것입니다.또한 어레이 슬롯을 기본값으로 초기화하는 비용을 피할 수 있다고 생각합니다.예를 들어, 다음과 같습니다.

bool[] vals = new bool[]{ false, true, false, !(a ||b) && c, SomeBoolMethod() };

어레이가 너무 크면 BitArray를 사용해야 합니다.모든 부울에 대해 바이트 대신 1비트를 사용하며(예: 부울 배열), 비트 연산자를 사용하여 모든 비트를 true로 설정할 수 있습니다.또는 true로 초기화합니다.하지만 한 번만 하면 된다면 비용이 더 들 뿐입니다.

System.Collections.BitArray falses = new System.Collections.BitArray(100000, false);
System.Collections.BitArray trues = new System.Collections.BitArray(100000, true);

// Now both contain only true values.
falses.And(trues);

2은 .NET Core 2.0을 지원합니다.Array.Fill()방법.

여기 샘플 코드가 있습니다.

var arr = new int[10];
int defaultValue = 2;
Array.Fill(arr,defaultValue);

또한 채워질 인덱스 범위에 대한 오버로드 방법도 있습니다.자세한 내용은 여기에서 확인할 수 있습니다.

유감스럽게도 직접적인 방법은 없다고 생각하지만, 어레이 클래스에 대한 확장 방법을 작성하여 이를 수행할 수 있다고 생각합니다.

class Program
{
    static void Main(string[] args)
    {
        int[] arr = new int[1000];
        arr.Init(10);
        Array.ForEach(arr, Console.WriteLine);
    }
}

public static class ArrayExtensions
{
    public static void Init<T>(this T[] array, T defaultVaue)
    {
        if (array == null)
            return;
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = defaultVaue;
        }
    }
}

조금 더 검색하고 읽은 후에 저는 다음을 발견했습니다.

bool[] bPrimes = new bool[1000000];
bPrimes = Array.ConvertAll<bool, bool>(bPrimes, b=> b=true);

제가 찾고 있는 것과 확실히 더 가깝습니다.하지만 for-loop의 원래 배열을 반복하고 값을 변경하는 것보다 더 나은지는 잘 모르겠습니다.실제로 빠른 테스트를 실시한 결과, 약 5배 정도 더 느리게 나타납니다.그렇다면 좋은 해결책은 아닙니다!

아래 코드는 작은 복사본과 배열에 대한 단순 반복을 결합한 것입니다.대용량 복사본의 경우 복사본

    public static void Populate<T>( T[] array, int startIndex, int count, T value ) {
        if ( array == null ) {
            throw new ArgumentNullException( "array" );
        }
        if ( (uint)startIndex >= array.Length ) {
            throw new ArgumentOutOfRangeException( "startIndex", "" );
        }
        if ( count < 0 || ( (uint)( startIndex + count ) > array.Length ) ) {
            throw new ArgumentOutOfRangeException( "count", "" );
        }
        const int Gap = 16;
        int i = startIndex;

        if ( count <= Gap * 2 ) {
            while ( count > 0 ) {
                array[ i ] = value;
                count--;
                i++;
            }
            return;
        }
        int aval = Gap;
        count -= Gap;

        do {
            array[ i ] = value;
            i++;
            --aval;
        } while ( aval > 0 );

        aval = Gap;
        while ( true ) {
            Array.Copy( array, startIndex, array, i, aval );
            i += aval;
            count -= aval;
            aval *= 2;
            if ( count <= aval ) {
                Array.Copy( array, startIndex, array, i, count );
                break;
            }
        }
    }

int[] 어레이를 사용하는 다양한 어레이 길이의 벤치마크는 다음과 같습니다.

         2 Iterate:     1981 Populate:     2845
         4 Iterate:     2678 Populate:     3915
         8 Iterate:     4026 Populate:     6592
        16 Iterate:     6825 Populate:    10269
        32 Iterate:    16766 Populate:    18786
        64 Iterate:    27120 Populate:    35187
       128 Iterate:    49769 Populate:    53133
       256 Iterate:   100099 Populate:    71709
       512 Iterate:   184722 Populate:   107933
      1024 Iterate:   363727 Populate:   126389
      2048 Iterate:   710963 Populate:   220152
      4096 Iterate:  1419732 Populate:   291860
      8192 Iterate:  2854372 Populate:   685834
     16384 Iterate:  5703108 Populate:  1444185
     32768 Iterate: 11396999 Populate:  3210109

첫 번째 열은 배열 크기이고, 그 다음에 간단한 반복을 사용하여 복사하는 시간입니다(@JaredPared 구현).이 방법의 시간은 그 이후입니다.이것들은 4개의 정수 구조의 배열을 사용하는 벤치마크입니다.

         2 Iterate:     2473 Populate:     4589
         4 Iterate:     3966 Populate:     6081
         8 Iterate:     7326 Populate:     9050
        16 Iterate:    14606 Populate:    16114
        32 Iterate:    29170 Populate:    31473
        64 Iterate:    57117 Populate:    52079
       128 Iterate:   112927 Populate:    75503
       256 Iterate:   226767 Populate:   133276
       512 Iterate:   447424 Populate:   165912
      1024 Iterate:   890158 Populate:   367087
      2048 Iterate:  1786918 Populate:   492909
      4096 Iterate:  3570919 Populate:  1623861
      8192 Iterate:  7136554 Populate:  2857678
     16384 Iterate: 14258354 Populate:  6437759
     32768 Iterate: 28351852 Populate: 12843259

. Core, . Standard > = 또는 .NET Core, .NET Standard > = 2.1 또는 시스템에 의존하는 경우.메리패사수있다습니도용할을 도 있습니다.Span<T>.Fill()방법:

var valueToFill = 165;
var data = new int[100];

data.AsSpan().Fill(valueToFill);

// print array content
for (int i = 0; i < data.Length; i++)
{
    Console.WriteLine(data[i]);
}

https://dotnetfiddle.net/UsJ9bu

병렬 구현은 어떻습니까?

public static void InitializeArray<T>(T[] array, T value)
{
    var cores = Environment.ProcessorCount;

    ArraySegment<T>[] segments = new ArraySegment<T>[cores];

    var step = array.Length / cores;
    for (int i = 0; i < cores; i++)
    {
        segments[i] = new ArraySegment<T>(array, i * step, step);
    }
    var remaining = array.Length % cores;
    if (remaining != 0)
    {
        var lastIndex = segments.Length - 1;
        segments[lastIndex] = new ArraySegment<T>(array, lastIndex * step, array.Length - (lastIndex * step));
    }

    var initializers = new Task[cores];
    for (int i = 0; i < cores; i++)
    {
        var index = i;
        var t = new Task(() =>
        {
            var s = segments[index];
            for (int j = 0; j < s.Count; j++)
            {
                array[j + s.Offset] = value;
            }
        });
        initializers[i] = t;
        t.Start();
    }

    Task.WaitAll(initializers);
}

배열을 초기화할 때만 이 코드의 힘을 볼 수는 없지만 "순수"에 대해서는 분명히 잊어야 한다고 생각합니다.

아니면... 단순히 역논리를 사용할 수도 있습니다.허락하다false의미하다true그리고 역도 성립.

코드샘플

// bool[] isVisible = Enumerable.Repeat(true, 1000000).ToArray();
bool[] isHidden = new bool[1000000]; // Crazy-fast initialization!

// if (isVisible.All(v => v))
if (isHidden.All(v => !v))
{
    // Do stuff!
}

여기에 제시된 많은 답변은 한 번에 하나의 요소를 어레이를 초기화하는 루프로 요약됩니다. 이 루프는 메모리 블록에서 한 번에 작동하도록 설계된 CPU 명령을 활용하지 않습니다.

.Net Standard 2.1(본 문서의 미리 보기)은 어레이를 제공합니다.Fill()은 런타임 라이브러리의 고성능 구현에 적합합니다(그러나 현재로서는 .NET Core가 이러한 가능성을 활용하지 않는 같습니다).

이전 플랫폼의 경우, 다음 확장 방법은 어레이 크기가 상당할 때 사소한 루프보다 성능이 훨씬 뛰어납니다.온라인 코드 챌린지에 대한 제 솔루션이 할당된 시간 예산보다 20% 정도 초과되었을 때 이를 만들었습니다.실행 시간을 약 70% 단축했습니다.이 경우 어레이 채우기는 다른 루프 내에서 수행되었으며 BLOCK_SIZE는 실험이 아닌 gut feel에 의해 설정되었습니다.일부 최적화는 가능합니다(예: 고정 크기 블록이 아닌 이미 설정된 모든 바이트를 원하는 값으로 복사).

internal const int BLOCK_SIZE = 256;
public static void Fill<T>(this T[] array, T value)
{
    if (array.Length < 2 * BLOCK_SIZE)
    {
        for (int i = 0; i < array.Length; i++) array[i] = value;
    }
    else
    {
        int fullBlocks = array.Length / BLOCK_SIZE;
        // Initialize first block
        for (int j = 0; j < BLOCK_SIZE; j++) array[j] = value;
        // Copy successive full blocks
        for (int blk = 1; blk < fullBlocks; blk++)
        {
            Array.Copy(array, 0, array, blk * BLOCK_SIZE, BLOCK_SIZE);
        }

        for (int rem = fullBlocks * BLOCK_SIZE; rem < array.Length; rem++)
        {
            array[rem] = value;
        }
    }
}

단순한 벤치마크:

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.18363.997 (1909/November2018Update/19H2)
Intel Core i7-6700HQ CPU 2.60GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.302
  [Host]        : .NET Core 3.1.6 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.31603), X64 RyuJIT
  .NET Core 3.1 : .NET Core 3.1.6 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.31603), X64 RyuJIT

Job=.NET Core 3.1  Runtime=.NET Core 3.1

|           Method |     Mean |     Error |    StdDev |
|----------------- |---------:|----------:|----------:|
| EnumerableRepeat | 2.311 us | 0.0228 us | 0.0213 us |
|  NewArrayForEach | 2.007 us | 0.0392 us | 0.0348 us |
|        ArrayFill | 2.426 us | 0.0103 us | 0.0092 us |
    [SimpleJob(BenchmarkDotNet.Jobs.RuntimeMoniker.NetCoreApp31)]
    public class InitializeArrayBenchmark {
        const int ArrayLength = 1600;

        [Benchmark]
        public double[] EnumerableRepeat() {
            return Enumerable.Repeat(double.PositiveInfinity, ArrayLength).ToArray();
        }

        [Benchmark]
        public double[] NewArrayForEach() {
            var array = new double[ArrayLength];

            for (int i = 0; i < array.Length; i++) {
                array[i] = double.PositiveInfinity;
            }

            return array;
        }

        [Benchmark]
        public double[] ArrayFill() {
            var array = new double[ArrayLength];
            Array.Fill(array, double.PositiveInfinity);

            return array;
        }
    }

이것도 효과가 있습니다...하지만 불필요할 수도 있습니다.

 bool[] abValues = new bool[1000];
 abValues = abValues.Select( n => n = true ).ToArray<bool>();

배열의 모든 요소를 단일 작업으로 설정할 수 있는 방법은 없습니다. 단, 해당 값이 요소 유형 기본값입니다.

할 수 : 예 들 어 배 경 으 다 인 같 우 과 한 연 번 있 수 습 니 다 모 산 설 로 할 정 정 으 의 두 를 이 수 로 음 열 , ▁eg ▁youArray.Clear(...)

여기 마이크로소프트가 포기한 프레임워크 사용자를 위한 다른 버전이 있습니다.Panos Theof의 솔루션과 Eric J'sPetar Petrov의 병렬 솔루션보다 4배 빠르고, 대규모 어레이의 경우 최대 2배 빠릅니다.

먼저 함수의 조상을 소개하겠습니다. 왜냐하면 코드를 이해하는 것이 더 쉽기 때문입니다.성능 측면에서 이는 Panos Theof의 코드와 거의 비슷하며 이미 충분할 수도 있습니다.

public static void Fill<T> (T[] array, int count, T value, int threshold = 32)
{
    if (threshold <= 0)
        throw new ArgumentException("threshold");

    int current_size = 0, keep_looping_up_to = Math.Min(count, threshold);

    while (current_size < keep_looping_up_to)
        array[current_size++] = value;

    for (int at_least_half = (count + 1) >> 1; current_size < at_least_half; current_size <<= 1)
        Array.Copy(array, 0, array, current_size, current_size);

    Array.Copy(array, 0, array, current_size, count - current_size);
}

보시다시피, 이는 이미 초기화된 부품을 반복적으로 두 배로 늘리는 것을 기반으로 합니다.이것은 간단하고 효율적이지만 현대적인 메모리 아키텍처에 위배됩니다.따라서 더블링만 사용하여 캐시 친화적인 시드 블록을 생성한 다음 대상 영역에서 반복적으로 블래칭하는 버전이 탄생했습니다.

const int ARRAY_COPY_THRESHOLD = 32;  // 16 ... 64 work equally well for all tested constellations
const int L1_CACHE_SIZE = 1 << 15;

public static void Fill<T> (T[] array, int count, T value, int element_size)
{
    int current_size = 0, keep_looping_up_to = Math.Min(count, ARRAY_COPY_THRESHOLD);

    while (current_size < keep_looping_up_to)
        array[current_size++] = value;

    int block_size = L1_CACHE_SIZE / element_size / 2;
    int keep_doubling_up_to = Math.Min(block_size, count >> 1);

    for ( ; current_size < keep_doubling_up_to; current_size <<= 1)
        Array.Copy(array, 0, array, current_size, current_size);

    for (int enough = count - block_size; current_size < enough; current_size += block_size)
        Array.Copy(array, 0, array, current_size, block_size);

    Array.Copy(array, 0, array, current_size, count - current_size);
}

참고: 이전 코드가 필요했습니다.(count + 1) >> 1더블링 루프에 대한 제한으로 최종 복사 작업이 남은 모든 것을 커버할 수 있는 충분한 피드를 확보합니다.홀수 카운트의 경우 다음과 같은 경우에는 그렇지 않습니다.count >> 1대신 사용하기로 했습니다.현재 버전에서는 선형 복사 루프가 느슨한 부분을 포착하기 때문에 이는 중요하지 않습니다.

배열 셀의 크기는 매개 변수로 전달되어야 합니다. 이는 - mindboggle - 제네릭이 나중에 사용할 수 있거나 사용할 수 없게 unmanaged될 수 있는 제약 조건()을 사용하지 않는 한 사용할 수 없기 때문입니다.잘못된 추정치는 큰 문제가 아니지만 다음과 같은 이유로 값이 정확할 경우 성능이 가장 좋습니다.

  • 요소 크기를 과소평가하면 블록 크기가 L1 캐시의 절반보다 클 수 있으므로 L1에서 복사 소스 데이터가 제거되고 느린 캐시 수준에서 다시 가져와야 할 가능성이 높아집니다.

  • 요소 크기를 과대평가하면 CPU의 L1 캐시 활용도가 낮아집니다. 즉, 선형 블록 복사 루프가 최적 활용도보다 더 자주 실행됩니다.따라서 고정 루프/통화 오버헤드는 엄격하게 필요한 것보다 더 많이 발생합니다.

다음은 내 코드와 경쟁하는 벤치마크입니다.Array.Clear그리고 앞에서 언급한 다른 세 가지 해결책.배열을 입니다.Int32[]캐시변등인로변줄위니다입해서이기을동한으화▁was▁. 각 테스트는 두 연속으로 되었고, 두 .각 테스트는 연속적으로 두 번 실행되었으며 두 번째 실행에 대한 시간이 소요되었습니다.

array size   Array.Clear      Eric J.   Panos Theof  Petar Petrov   Darth Gizka
-------------------------------------------------------------------------------
     1000:       0,7 µs        0,2 µs        0,2 µs        6,8 µs       0,2 µs 
    10000:       8,0 µs        1,4 µs        1,2 µs        7,8 µs       0,9 µs 
   100000:      72,4 µs       12,4 µs        8,2 µs       33,6 µs       7,5 µs 
  1000000:     652,9 µs      135,8 µs      101,6 µs      197,7 µs      71,6 µs 
 10000000:    7182,6 µs     4174,9 µs     5193,3 µs     3691,5 µs    1658,1 µs 
100000000:   67142,3 µs    44853,3 µs    51372,5 µs    35195,5 µs   16585,1 µs 

만약 이 코드의 성능이 충분하지 않다면 유망한 방법은 선형 복사 루프(모든 스레드가 동일한 소스 블록을 사용함) 또는 우리의 오랜 친구 P/Invoke를 병렬화하는 것입니다.

및으로 MMX 환경에서는 ": 블참지고채우것고우는은일명반으적로록을사고 MMX/▁the▁note▁callive▁moral▁simply▁using▁is▁routines참▁that▁ofent▁would▁clearing고ment▁ofnot▁one▁decent▁blocks수의루x▁fillings,런로▁environ,▁so▁and▁runtimeions므되해▁highly행:▁any에▁to▁by 적절한 환경에서는 단순히 각각의 도덕적 동등성이라고 할 수 있습니다.std::memset전문적인 수준의 성능을 보장합니다.IOW, 권한에 따라 라이브러리 기능Array.Clear손으로 말아서 만든 것들은 모두 먼지 속에 남겨두어야 합니다.그것이 그 반대라는 사실은 상황이 실제로 얼마나 터무니없는 것인지 보여줍니다.자신의 것을 굴려야 하는 것도 마찬가지입니다.Fill<>첫째, 아직 Core와 Standard에만 있지만 Framework에는 없기 때문입니다. .NET은 거의 20년 동안 존재해 왔으며 여전히 가장 기본적인 것들을 위해 왼쪽과 오른쪽으로 P/Invoke를 하거나 우리만의 것을 굴려야 합니다.

배열에서 몇 개의 값만 설정할 계획이지만 대부분의 경우 (사용자 지정) 기본값을 사용하려면 다음과 같은 방법을 사용할 수 있습니다.

public class SparseArray<T>
{
    private Dictionary<int, T> values = new Dictionary<int, T>();

    private T defaultValue;

    public SparseArray(T defaultValue)
    {
        this.defaultValue = defaultValue;
    }

    public T this [int index]
    {
      set { values[index] = value; }
      get { return values.ContainsKey(index) ? values[index] ? defaultValue; }
    }
}

어레이 자체와 같이 다른 인터페이스를 구현하여 유용하게 사용해야 할 수도 있습니다.

저는 아무도 매우 간단하면서도 매우 빠른 SIMD 버전을 만들지 않았다는 것에 약간 놀랐습니다.

  public static void PopulateSimd<T>(T[] array, T value) where T : struct
  {
     var vector = new Vector<T>(value);
     var i = 0;
     var s = Vector<T>.Count;
     var l = array.Length & ~(s-1);
     for (; i < l; i += s) vector.CopyTo(array, i);
     for (; i < array.Length; i++) array[i] = value;
  }

벤치마크: (Framework 4.8의 수치이지만 Core 3.1은 통계적으로 동일합니다.)

방법 | N | 평균 | 오차 | 표준 편차 | 비율 | 비율SD ||----------- |-------- |---------------:|---------------:|--------------:|------:|--------:|다스 기즈카 | 10 | 25.975 ns | 1.2430 ns | 0.1924 ns | 1.00 | 0.00 |심드 | 10 | 3.438 ns | 0.4427 ns | 0.0685 ns | 0.13 | 0.00 ||            |         |                |                |               |       |         |다스 기즈카 | 100 | 81.155ns | 3.8287ns | 0.2099ns | 1.00 | 0.00ns |심드 | 100 | 12.178 ns | 0.4547 ns | 0.0704 ns | 0.15 | 0.00 ||            |         |                |                |               |       |         |다스 기즈카 | 1000 | 201.138 ns | 8.9769 ns | 1.3892 ns | 1.00 | 0.00 |심드 | 1000 | 100.397 ns | 4.0965 ns | 0.6339 ns | 0.50 | 0.00 ||            |         |                |                |               |       |         |다스 기즈카 | 10000 | 1,292.660 ns | 38.4965 ns | 5.9574 ns | 1.00 | 0.00 |심드 | 10000 | 1,272.819 ns | 68.5148 ns | 10.6027 ns | 0.98 | 0.01 ||            |         |                |                |               |       |         |다스 기즈카 | 100000 | 16,156.106 ns | 366.1133 ns | 56.6564 ns | 1.00 | 0.00 |심드 | 100000 | 17,627.879 ns | 1,589.7423 ns | 246.0144 ns | 1.09 | 0.02 ||            |         |                |                |               |       |         |DarthGizka | 1000000 | 176,625.870 ns | 32,235.9957 ns | 1,766.9637 ns | 1.00 | 0.00 |심드 | 1000000 | 186,812.920 ns | 18,069.1517 ns | 2,796.2212 ns | 1.07 | 0.01 |

볼 수 있듯이, 그것은 <10000개의 원소들>에서 훨씬 더 빠르며, 그 이상으로 약간 느릴 뿐입니다.

제가 파티에 늦었다는 것은 알지만 여기 아이디어가 있습니다.랩핑된 값으로 변환 연산자가 있는 래퍼를 작성하여 랩핑된 유형의 스탠드인으로 사용할 수 있도록 합니다.이것은 실제로 @l33t의 바보 같은 대답에서 영감을 받았습니다.

먼저 (C++에서 온) C#에서 배열의 요소가 구성될 때 기본 벡터가 호출되지 않는다는 것을 깨달았습니다.대신 사용자 정의 기본 생성자가 있는 경우에도 모든 배열 요소가 초기화되지 않습니다.깜짝 놀랐어요.

따라서 단순히 원하는 값의 기본 cctor를 제공하는 래퍼 클래스는 C++의 배열에서는 작동하지만 C#에서는 작동하지 않습니다.해결 방법은 변환 시 래퍼 유형 0이 원하는 시드 값에 매핑되도록 하는 것입니다.이러한 방식으로 제로 초기화 값은 모든 실용적인 목적을 위해 시드와 함께 초기화되는 것으로 보입니다.

public struct MyBool
{
    private bool _invertedValue;

    public MyBool(bool b) 
    {   
        _invertedValue = !b;
    }

    public static implicit operator MyBool(bool b)
    {
        return new MyBool(b);
    }

    public static implicit operator bool(MyBool mb)
    {
        return !mb._invertedValue;
    }

}

static void Main(string[] args)
{
        MyBool mb = false; // should expose false.
        Console.Out.WriteLine("false init gives false: " 
                              + !mb);

        MyBool[] fakeBoolArray = new MyBool[100];

        Console.Out.WriteLine("Default array elems are true: " 
                              + fakeBoolArray.All(b => b) );

        fakeBoolArray[21] = false;
        Console.Out.WriteLine("Assigning false worked: " 
                              + !fakeBoolArray[21]);

        fakeBoolArray[21] = true;
        // Should define ToString() on a MyBool,
        // hence the !! to force bool
        Console.Out.WriteLine("Assigning true again worked: " 
                              + !!fakeBoolArray[21]);
}

이 패턴은 모든 값 유형에 적용됩니다.예를 들어 4로 초기화를 원하는 경우 int에 대해 0부터 4까지 매핑할 수 있습니다.

시드 값을 템플릿 매개 변수로 제공하여 C++에서 가능한 대로 템플릿을 만들고 싶지만 C#에서는 불가능한 것으로 알고 있습니다.아니면 제가 뭔가를 놓치고 있는 것일까요? (물론 C++ 매핑에서는 배열 요소에 대해 호출될 기본 cctor를 제공할 수 있기 때문에 전혀 필요하지 않습니다.)

FWIW, 여기 C++에 해당하는 것이 있습니다: https://ideone.com/wG8yEh .

논리를 뒤집을 수 있는 경우 다음을 사용할 수 있습니다.Array.Clear()부울 배열을 false로 설정하는 메서드입니다.

        int upperLimit = 21;
        double optimizeMe = Math.Sqrt(upperLimit);

        bool[] seiveContainer = new bool[upperLimit];
        Array.Clear(seiveContainer, 0, upperLimit);

이에 대한 답변이 몇 가지 더 있습니다(복사본?).질문:.C#에서 memset에 해당하는 것은 무엇입니까?

누군가가 대안을 벤치마킹했습니다(안전하지 않은 버전을 포함했지만 시도하지 않았습니다).memset): http://techmikael.blogspot.co.uk/2009/12/filling-array-with-default-value.html

다음은 에 대한 또 다른 평가입니다.System.Collections.BitArray그런 생성자를 가진.

bool[] result = new BitArray(1000000, true).Cast<bool>().ToArray();

또는

bool[] result = new bool[1000000];
new BitArray(1000000, true).CopyTo(result, 0);

배열을 만드는 내부에 개인 클래스를 만들고 이를 위한 getter와 setter를 만듭니다.배열의 각 위치가 임의와 같이 고유한 것이어야 하는 경우를 제외하고 int?를 배열로 사용한 다음 위치가 동일한 null이면 해당 위치를 채우고 새 임의 값을 반환합니다.

IsVisibleHandler
{

  private bool[] b = new bool[10000];

  public bool GetIsVisible(int x)
  {
  return !b[x]
  }

  public void SetIsVisibleTrueAt(int x)
  {
  b[x] = false //!true
  }
}

또는 사용

public void SetIsVisibleAt(int x, bool isTrue)
{
b[x] = !isTrue;
}

세터.

Boolean[] data = new Boolean[25];

new Action<Boolean[]>((p) => { BitArray seed = new BitArray(p.Length, true); seed.CopyTo(p, 0); }).Invoke(data);

언급URL : https://stackoverflow.com/questions/1014005/how-to-populate-instantiate-a-c-sharp-array-with-a-single-value

반응형