사전을 반복하는 가장 좋은 방법은 무엇입니까?


2625

C #에서 사전을 반복하는 몇 가지 방법을 보았습니다. 표준적인 방법이 있습니까?


108
나는이 질문에 대한 많은 답변이 923 번 제기 된 것과 함께 놀랐습니다 .. (물론 사용합니다.). IMHO가 적절하지 않은 방식으로 사전이 남용되는 것을 보았 기 때문에이 의견을 말해야했습니다. 사전을 반복하는 방법을 궁금해하기 전에 염두에 두십시오.
Vikas Gupta

74
@VikasGupta 키가 무엇인지 모르는 경우 키-값 쌍 모음으로 무언가를 수행하기 위해 제안하는 것은 무엇입니까?
nasch

26
@displayName 각 키-값 쌍으로 무언가를하고 싶지만 값을 찾는 데 사용할 키에 대한 참조가 없다면 사전을 반복해야합니까? Vikas의 주장이 일반적으로 잘못된 사용법이라는 주장에도 불구하고 당신이 그렇게하고 싶을 때가있을 수 있다고 지적했습니다.
nasch

34
사용법이 잘못되었다는 것은 더 나은 대안이 있다는 것을 의미합니다. 그 대안은 무엇입니까?
Kyle Delaney 2016 년

40
VikasGupta가 잘못되었습니다. 비 이론적 시나리오에서 수년간 고성능 C # 및 C ++ 프로그래밍을 한 후에도 확인하실 수 있습니다. 실제로 사전을 만들고 고유 한 키-값 쌍을 저장 한 다음 컬렉션 내에서 고유 한 키가있는 것으로 입증 된 이러한 값을 반복하는 경우가 자주 있습니다. 추가 컬렉션을 만드는 것은 사전 반복을 피하는 비효율적이고 비용이 많이 드는 방법입니다. 귀하의 견해를 명확히하는 질문에 대한 답변으로 좋은 대안을 제공하십시오. 그렇지 않으면 귀하의 의견은 의미가 없습니다.
sɐunıɔ ןɐ qɐp

답변:


3711
foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

29
사전의 키 / 값 유형을 정확히 모르면 어떻게해야합니까? var entry이 경우 사용하는 것이 더 좋으므로 위의 답변 대신 두 번째 모양 으로이 답변 에 투표 했습니다 .
Ozair Kafray

93
@OzairKafray var는 유형이 일반적으로 나쁜 습관인지 모르는 경우에 사용 합니다.
Nate

52
Pablo가 반환 유형을 난독 화하는 게으른 코더 "var"사용법을 기본값으로 사용하지 않았기 때문에이 답변이 우수합니다.
MonkeyWrench

119
@MonkeyWrench : Meh. Visual Studio는 유형이 무엇인지 알고 있습니다. 알아 내기 위해 변수 위에 마우스를 올리면됩니다.
Robert Harvey

31
내가 이해하는 것처럼 var컴파일 타임에 유형이 알려진 경우에만 작동합니다. Visual Studio에서 유형을 알고 있으면 해당 유형도 찾을 수 있습니다.
Kyle Delaney

866

C #에서 일반 사전을 사용하려는 경우 다른 언어로 연관 배열을 사용하십시오.

foreach(var item in myDictionary)
{
  foo(item.Key);
  bar(item.Value);
}

또는 키 컬렉션 만 반복해야하는 경우

foreach(var item in myDictionary.Keys)
{
  foo(item);
}

마지막으로, 값에만 관심이 있다면 :

foreach(var item in myDictionary.Values)
{
  foo(item);
}

합니다 (참고를 타고 var키워드는 선택의 C # 3.0 기능 이상, 당신은 또한 여기에 키 / 값의 정확한 유형을 사용할 수 있습니다)


11
var에 기능이 가장 첫 번째 코드 블록 :) 필요
nawfal

27
이 답변은 키 또는 값을 명시 적으로 반복 할 수 있음을 지적합니다.
Rotsiser Mho

11
나는 var를 사용하는 것을 좋아하지 않는다. 그것이 단지 구문 설탕이라는 것을 감안할 때, 왜 그것을 여기에서 사용합니까? 누군가 코드를 읽으려고 할 때 코드의 종류를 결정하기 위해 코드를 뛰어 넘어야 myDictionary합니다 (실제 이름이 아닌 한). 나는 타입이 명백 할 때 var를 사용하는 것이 좋다고 생각한다. var x = "some string"그러나 즉시 명백하지 않을 때 나는 코드 판독기 / 검토
자를

8
var제 생각에는 드물게 사용해야합니다. 특히 여기서는 건설적이지 않습니다. 유형 KeyValuePair이 질문과 관련이있을 수 있습니다.
Sinjai

3
var독특한 목적을 가지고 있으며 그것이 '구문 적'설탕이라고 믿지 않습니다. 의도적으로 사용하는 것이 적절한 방법입니다.
Joshua K

159

경우에 따라 for 루프 구현에서 제공 할 수있는 카운터가 필요할 수 있습니다. 이를 위해 LINQ는 ElementAt다음을 지원합니다.

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}

21
'.ElementAt'메소드를 사용하려면 다음을 기억하십시오. using System.Linq; 이것은 fx에 포함되지 않습니다. 자동 생성 된 테스트 클래스.
Tinia

14
키와 관련된 값을 수정하는 경우이 방법을 사용하십시오. 그렇지 않으면 foreach ()를 수정하고 사용할 때 예외가 발생합니다.
Mike de Klerk

27
아닌가 ElementAtO (n)이 작업은?
Arturo Torres Sánchez

162
이 답변은 너무 많은 공감대를받을 자격이 없습니다. 사전에는 암시 적 순서 .ElementAt가 없으므로이 컨텍스트에서 사용 하면 미묘한 버그가 발생할 수 있습니다. 위의 Arturo의 요점은 훨씬 더 심각합니다. 사전 dictionary.Count + 1시간을 반복하여 O (n)이어야하는 연산에 대해 O (n ^ 2) 복잡성을 초래합니다. 실제로 인덱스가 필요한 경우 (아마도 처음에 잘못된 컬렉션 유형을 사용하고있는 경우) dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})대신 반복 .ElementAt하여 루프 내부에서 사용하지 않아야합니다 .
쓰셨

5
ElementAt-o (n) 조작! 진심이야? 이것은 당신이 그것을해서는 안되는 방법의 예입니다. 이 많은 공짜?
Mukesh Adhvaryu

96

키 또는 값 뒤에 있는지 여부에 따라 다릅니다.

MSDN Dictionary(TKey, TValue)클래스 설명에서 :

// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
    Console.WriteLine("Key = {0}, Value = {1}", 
        kvp.Key, kvp.Value);
}

// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
    openWith.Values;

// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
    Console.WriteLine("Value = {0}", s);
}

// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
    openWith.Keys;

// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
    Console.WriteLine("Key = {0}", s);
}

82

일반적으로 특정 컨텍스트없이 "최상의 방법"을 요구 하는 것은 최상의 색상이 무엇인지 묻는 것과 같습니다 .

한 손으로 많은 색상이 있으며 최상의 색상이 없습니다. 그것은 필요와 종종 맛에 달려 있습니다.

반면에 C #에서 Dictionary를 반복하는 방법은 여러 가지가 있으며 최선의 방법은 없습니다. 그것은 필요와 종종 맛에 달려 있습니다.

가장 간단한 방법

foreach (var kvp in items)
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

값만 필요한 경우 (을 호출 할 수 item있으며보다 읽기 쉽습니다 kvp.Value).

foreach (var item in items.Values)
{
    doStuff(item)
}

특정 정렬 순서가 필요한 경우

일반적으로 초보자는 사전의 열거 순서에 놀랐습니다.

LINQ는 순서 (및 기타 여러 가지)를 지정할 수있는 간결한 구문을 제공합니다.

foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

다시 한 번만 값이 필요할 수 있습니다. LINQ는 또한 다음과 같은 간결한 솔루션을 제공합니다.

  • 값을 직접 반복하십시오 (호출하기 item쉽고보다 읽기 쉽습니다 kvp.Value)
  • 그러나 키로 정렬

여기있어:

foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
    doStuff(item)
}

이 예제에서 수행 할 수있는 더 많은 실제 사용 사례가 있습니다. 특정 주문이 필요하지 않은 경우 "가장 간단한 방법"(위 참조)을 고수하십시오!


마지막 .Values은 select 절이 아니 어야합니다 .
Mafii

@Mafii 확실합니까? OrderBy가 리턴 한 값은 KeyValuePair 유형이 아니며 Value필드 가 없습니다 . 내가 본 정확한 유형은 IOrderedEnumerable<KeyValuePair<TKey, TValue>>입니다. 아마도 다른 의미가 있습니까? 당신이 의미하는 바를 보여주는 완전한 줄을 작성할 수 있습니까?
Stéphane Gourichon

:이 대답은 내가 무슨 뜻인지 포함 생각 stackoverflow.com/a/141105/5962841을 하지만, 내가 뭔가 혼동하는 경우 정정 해줘
Mafii

1
@Mafii 내 대답 전체를 다시 읽으십시오. 코드 섹션 사이의 설명은 컨텍스트를 알려줍니다. 당신이 언급 한 대답은 내 대답의 두 번째 코드 섹션과 같습니다 (주문 필요 없음). 내가 방금 items.Value제안한대로 썼습니다 . 네 번째로 언급 한 섹션의 경우 키-값 쌍 대신 사전의 값을 직접 열거 Select()하는 방법 foreach입니다. 이 경우에 마음에 들지 않으면 Select()세 번째 코드 섹션을 선호 할 수 있습니다. 네 번째 섹션의 요점은 LINQ로 컬렉션을 사전 처리 할 수 ​​있음을 보여주는 것입니다.
Stéphane Gourichon

1
그렇게 .Keys.Orderby()하면 키 목록을 반복하게됩니다. 그게 전부라면 괜찮습니다. 값이 필요한 경우 루프에서 각 키의 사전을 쿼리하여 값을 가져와야합니다. 많은 시나리오에서 실질적인 차이는 없습니다. 고성능 시나리오에서는 가능합니다. 내가 대답의 시작 부분에 쓴 것처럼 : "많은 방법이 있지만 (...) 최선의 방법은 없습니다. 그것은 또한 필요에 따라 맛에 달려 있습니다."
Stéphane Gourichon

53

나는 foreach가 표준 방법이라고 말하고 싶지만 분명히 당신이 찾고있는 것에 달려 있습니다.

foreach(var kvp in my_dictionary) {
  ...
}

찾고 계십니까?


42
음, "값"이라는 항목의 이름을 지정하는 것이 혼란스럽지 않습니까? 일반적으로 "value.Key"및 "value.Value"와 같은 구문을 사용합니다.이 코드는 코드를 읽는 다른 사람, 특히 .Net Dictionary의 구현 방법에 익숙하지 않은 사용자에게는 그다지 직관적이지 않습니다. .
RenniePet

3
@RenniePet kvp은 일반적으로 사전 및 관련 데이터 구조를 반복 할 때 KeyValuePair 인스턴스의 이름을 지정하는 데 사용됩니다 foreach(var kvp in myDictionary){....
mbx

37

멀티 스레드 처리를 위해 큰 사전에서이를 시도 할 수도 있습니다.

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});

8
@WiiMaxx 그리고이 아이템들이 서로 의존하지 않는다면 더 중요합니다
Mafii

36

C # 7.0 에는 Deconstructors가 도입되었으며 .NET Core 2.0+ 응용 프로그램을사용하는 경우KeyValuePair<>이미구조체가 포함Deconstruct()되어 있습니다. 그래서 당신은 할 수 있습니다 :

var dic = new Dictionary<int, string>() { { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
foreach (var (key, value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}
//Or
foreach (var (_, value) in dic) {
    Console.WriteLine($"Item [NO_ID] = {value}");
}
//Or
foreach ((int key, string value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}

여기에 이미지 설명을 입력하십시오


5
최소한 4.7.2까지 KeyValuePair에 대한 Deconstruct가없는 .NET Framework를 사용하는 경우 다음을 시도하십시오.foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
nwsmith

29

이 질문에 이미 많은 답변이 있었지만 약간의 연구를하고 싶었습니다.

배열과 같은 것을 반복하는 것과 비교할 때 사전을 반복하는 것이 다소 느릴 수 있습니다. 내 테스트에서 배열에 대한 반복은 0.015003 초가 걸리고 사전 (동일한 수의 요소가있는)에 대한 반복은 0.0365073 초가 걸리는 2.4 배입니다! 나는 훨씬 더 큰 차이를 보았지만. 비교를 위해 List는 0.00215043 초 사이에있었습니다.

그러나 그것은 사과와 오렌지를 비교하는 것과 같습니다. 내 요점은 사전을 반복하는 것이 느리다는 것입니다.

사전은 조회에 최적화되어 있으므로이를 염두에두고 두 가지 방법을 만들었습니다. 하나는 단순히 foreach를 수행하고 다른 하나는 키를 반복 한 다음 조회합니다.

public static string Normal(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var kvp in dictionary)
    {
        value = kvp.Value;
        count++;
    }

    return "Normal";
}

이것은 키를로드하고 대신 반복합니다 (키를 문자열로 가져 오려고 시도했지만 차이는 무시할 만했습니다.

public static string Keys(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var key in dictionary.Keys)
    {
        value = dictionary[key];
        count++;
    }

    return "Keys";
}

이 예제에서 일반 foreach 테스트는 0.0310062를, 키 버전은 0.2205441을 사용했습니다. 모든 키를로드하고 모든 조회를 반복하는 것은 분명히 느립니다!

최종 테스트를 위해 여기에서 키를 사용하면 이점이 있는지 확인하기 위해 반복을 10 번 수행했습니다 (이 시점에서 나는 단지 궁금했습니다).

진행 상황을 시각화하는 데 도움이되는 RunTest 메소드가 있습니다.

private static string RunTest<T>(T dictionary, Func<T, string> function)
{            
    DateTime start = DateTime.Now;
    string name = null;
    for (int i = 0; i < 10; i++)
    {
        name = function(dictionary);
    }
    DateTime end = DateTime.Now;
    var duration = end.Subtract(start);
    return string.Format("{0} took {1} seconds", name, duration.TotalSeconds);
}

여기에서 정상적인 foreach 실행은 0.2820564 초가 걸렸습니다 (예상대로 단일 반복보다 약 10 배 길었습니다). 키를 반복하는 데 2.2249449 초가 걸렸습니다.

추가 편집 : 다른 답변 중 일부를 읽으면 Dictionary 대신 Dictionary를 사용하면 어떻게 될지 의문이 생겼습니다. 이 예제에서 배열은 0.0120024 초, 목록 0.0185037 초 및 사전 0.0465093 초가 걸렸습니다. 데이터 유형이 사전의 속도를 얼마나 느리게 만드는지 예상하는 것이 합리적입니다.

내 결론은 무엇입니까 ?

  • 가능한 경우 사전을 반복하지 마십시오. 사전에 동일한 데이터가있는 배열을 반복하는 것보다 속도가 느립니다.
  • 사전을 반복하도록 선택하면 너무 영리하려고하지 마십시오. 느리기는하지만 표준 foreach 방법을 사용하는 것보다 훨씬 나쁠 수 있습니다.

11
DateTime 대신 stopWatch
Even Mien

2
테스트 시나리오, 사전에 몇 개의 항목이 있는지, 평균 시간을 계산하기 위해 얼마나 자주 시나리오를 실행 했습니까?
WiiMaxx

3
흥미롭게도 사전에 어떤 데이터가 있는지에 따라 다른 결과를 얻을 수 있습니다. Dictionary를 종료하는 동안 Enumerator 함수는 사전에서 많은 빈 슬롯을 건너 뛰어야하므로 배열을 반복하는 것보다 속도가 느려집니다. 사전이 가득 차면 절반이 비어있는 경우보다 건너 뛸 빈 슬롯이 줄어 듭니다.
Martin Brown

26

많은 옵션이 있습니다. 내가 개인적으로 가장 좋아하는 것은 KeyValuePair입니다

Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary)
{
     // Do some interesting things
}

키 및 값 컬렉션을 사용할 수도 있습니다


14

함께 .NET Framework 4.7하나가 사용할 수있는 분해를

var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
    Console.WriteLine(fruit + ": " + number);
}

이 코드가 낮은 C # 버전에서 작동하게하려면 System.ValueTuple NuGet package어딘가에 추가 하고 작성하십시오.

public static class MyExtensions
{
    public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple,
        out T1 key, out T2 value)
    {
        key = tuple.Key;
        value = tuple.Value;
    }
}

9
이것은 올바르지 않습니다. .NET 4.7은 간단하게 ValueTuple내장되어 있습니다. 이전 버전의 너겟 패키지로 제공됩니다. 더 중요한 것은 C # 7.0+가 Deconstruct메소드가 해체 자로 작동 하기 위해 필요하다는 것 입니다 var (fruit, number) in fruits.
David Arno

13

C # 7부터는 객체를 변수로 분해 할 수 있습니다. 나는 이것이 사전을 반복하는 가장 좋은 방법이라고 생각합니다.

예:

이를 확장하는 확장 메소드를 작성하십시오 KeyValuePair<TKey, TVal>.

public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey key, out TVal value)
{
   key = pair.Key;
   value = pair.Value;
}

Dictionary<TKey, TVal>다음과 같은 방식으로 반복

// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();

// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
   Console.WriteLine($"{key} : {value}");
}

10

아래에서 반복하도록 제안했습니다.

Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary) {
    //Do some interesting things;
}

참고로, foreach값이 object 유형 인 경우 작동하지 않습니다.


4
정교한하십시오 foreach경우 작동하지 않습니다 어떤 값이 타입이다 object? 그렇지 않으면 이것은 의미가 없습니다.
Marc L.

9

사전을 반복하는 가장 간단한 양식 :

foreach(var item in myDictionary)
{ 
    Console.WriteLine(item.Key);
    Console.WriteLine(item.Value);
}

9

C # 7을 사용 하여 솔루션의 모든 프로젝트 에이 확장 메소드 를 추가 하십시오.

public static class IDictionaryExtensions
{
    public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
        this IDictionary<TKey, TValue> dict)
    {
        foreach (KeyValuePair<TKey, TValue> kvp in dict)
            yield return (kvp.Key, kvp.Value);
    }
}


이 간단한 구문을 사용하십시오

foreach (var(id, value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


아니면 이걸 원한다면

foreach ((string id, object value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


전통 대신

foreach (KeyValuePair<string, object> kvp in dict)
{
    string id = kvp.Key;
    object value = kvp.Value;

    // your code using 'id' and 'value'
}


확장 메서드는 KeyValuePairIDictionary<TKey, TValue>형식을 강력한 형식으로 변환 tuple하여이 새로운 편안한 구문을 사용할 수 있습니다.

필수 사전 항목을로만 tuples변환하므로 전체 사전을로 변환하지 tuples않으므로 이와 관련된 성능 문제가 없습니다.

tuple사용 하는 것과 비교 하여 확장 메소드를 호출하는 데 약간의 비용이 듭니다 .KeyValuePair직접 적습니다. 어쨌든 KeyValuePair의 속성 KeyValue새 루프 변수를 지정하는 경우에는 문제가되지 않습니다 .

실제로,이 새로운 구문은 저수준 초 고성능 시나리오를 제외하고는 대부분의 경우에 매우 적합합니다.이 시나리오에서는 여전히 특정 지점에서 사용하지 않는 옵션이 있습니다.

이 체크 아웃 : MSDN 블로그 - 새로운 C의 기능 # 7


1
키-값 쌍보다 '편안한'튜플을 선호하는 이유는 무엇입니까? 나는 여기에 이익이 보이지 않습니다. 튜플에는 키와 값이 포함되어 있으므로 키-값 쌍도 있습니다.
Maarten

4
안녕하십니까, 귀하의 질문에 감사드립니다. 주요 이점은 추가적인 프로그래밍 노력없이 코드를 읽을 수 있다는 것입니다. KeyValuePair를 사용하면 항상 양식 kvp.Keykvp.Value각각의 키와 값을 사용해야합니다 . 튜플을 사용하면 foreach 블록 내에서 추가 변수 선언을 사용하지 않고도 키와 값의 이름을 유연하게 지정할 수 있습니다. 예를 들어 키의 이름을으로 factoryName, 값을으로 models지정할 수 있습니다. 이는 중첩 루프 (사전의 사전)를 얻을 때 특히 유용합니다. 코드 유지 관리가 훨씬 쉬워집니다. 시도해보십시오! ;-)
sɐunıɔ ןɐ qɐp

7

나는 이것이 매우 오래된 질문이라는 것을 알고 있지만 유용한 확장 방법을 만들었습니다.

    public static void ForEach<T, U>(this Dictionary<T, U> d, Action<KeyValuePair<T, U>> a)
    {
        foreach (KeyValuePair<T, U> p in d) { a(p); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.KeyCollection k, Action<T> a)
    {
        foreach (T t in k) { a(t); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.ValueCollection v, Action<U> a)
    {
        foreach (U u in v) { a(u); }
    }

이 방법으로 다음과 같은 코드를 작성할 수 있습니다.

myDictionary.ForEach(pair => Console.Write($"key: {pair.Key}, value: {pair.Value}"));
myDictionary.Keys.ForEach(key => Console.Write(key););
myDictionary.Values.ForEach(value => Console.Write(value););

6

때때로 값을 열거해야하는 경우 사전의 값 콜렉션을 사용하십시오.

foreach(var value in dictionary.Values)
{
    // do something with entry.Value only
}

이 게시물에 의해 가장 빠른 방법이라고 알려졌습니다 : http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html


실제로 성능을 가져 오려면 +1입니다. 실제로 사전 자체를 반복하면 필요한 값만 있으면 오버 헤드가 발생합니다. 이는 주로 값 또는 참조를 KeyValuePair 구조체에 복사하기 때문입니다.
Jaanus Varus

1
참고로 해당 링크의 마지막 테스트는 잘못된 테스트입니다. 키를 반복하여 값을 무시하고 이전 두 테스트는 값을 사용합니다.
Crescent Fresh

5

MSDN의 DictionaryBase 클래스 설명서에서이 방법을 찾았습니다.

foreach (DictionaryEntry de in myDictionary)
{
     //Do some stuff with de.Value or de.Key
}

이것은 DictionaryBase에서 상속받은 클래스에서 올바르게 작동 할 수있는 유일한 방법이었습니다.


3
이것은 제네릭이 아닌 버전의 Dictionary를 사용할 때와 같습니다 (즉, .NET Framework 2.0 이전).
joedotnot

@ joed0tnot : Hashtable객체에 사용되는 비 제네릭 버전입니다.
sɐunıɔ ןɐ qɐp

5

foreach반복 ___.Values이 빠르면 더 빠릅니다.

여기에 이미지 설명을 입력하십시오


왜 전화하는 ContainsKey()for버전? 이것은 비교중인 코드에없는 추가 오버 헤드를 추가합니다. TryGetValue()정확한 "키가 있으면 항목을 키로 가져옵니다"패턴을 대체합니다. 경우 또한, dict의 정수의 연속 된 범위에 포함 0로를 dictCount - 1, 당신은 인덱서가 실패 할 수있어, 그렇지 않으면 dict.Keys반복해야합니다. 어느 쪽이든은, 아니 ContainsKey()/ TryGetValue()이 필요했다. 마지막으로, 코드 스크린 샷을 게시하지 마십시오.
BACON

3

.NET 4.0 이상을 활용하고 원래 승인 된 것에 대한 업데이트 된 답변을 제공합니다.

foreach(var entry in MyDic)
{
    // do something with entry.Value or entry.Key
}

3

MSDN의 공식 문서에 따르면 사전을 반복하는 표준 방법은 다음과 같습니다.

foreach (DictionaryEntry entry in myDictionary)
{
     //Read entry.Key and entry.Value here
}

2

사전을 반복하는 확장 프로그램을 작성했습니다.

public static class DictionaryExtension
{
    public static void ForEach<T1, T2>(this Dictionary<T1, T2> dictionary, Action<T1, T2> action) {
        foreach(KeyValuePair<T1, T2> keyValue in dictionary) {
            action(keyValue.Key, keyValue.Value);
        }
    }
}

그럼 당신은 전화 할 수 있습니다

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));

당신은 당신이 가진 ForEach방법을 정의했습니다 foreach (...) { }... 불필요한 것 같습니다.
Maarten

1

말하자면, 기본적으로 값 컬렉션을 반복하려면 IEnumerable <>을 구현할 수 있다고 생각합니다. 여기서 T는 사전의 값 개체 유형이며 "this"는 사전입니다.

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}

1

대부분의 대답은 foreach-loop와 관련되어 있으므로 2 센트를 추가하고 싶었습니다. 다음 코드를 살펴보십시오.

Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>();

//Add some entries to the dictionary

myProductPrices.ToList().ForEach(kvP => 
{
    kvP.Value *= 1.15;
    Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value));
});

이로 인해 '.ToList ()'의 추가 호출이 추가 되었으므로 큰 사전으로 작업하고 병렬로 실행할 때 간헐적 으로 약간의 성능 향상이있을 수 있습니다 (여기에서 foreach vs someList.Foreach () {} ). 옵션 / 전혀 영향을 미치지 않습니다.

또한 foreach 루프 내에서 'Value'속성에 값을 할당 할 수 없습니다. 반면에 '키'도 조작 할 수있어 런타임시 문제가 발생할 수 있습니다.

키와 값을 "읽고"싶을 때 IEnumerable.Select ()를 사용할 수도 있습니다.

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );

5
아무런 이유없이 전체 컬렉션을 복사 해도 성능이 향상 되지 않습니다 . 추가 메모리를 거의 소비하지 않아야하는 코드의 메모리 공간을 두 배로 늘릴뿐만 아니라 코드 속도를 크게 느리게합니다.
Servy

부작용 'List.ForEach'방법을 피하십시오 : foreach부작용 가시성을 강제로 올리십시오.
user2864740

0
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));

2
이 답변에는 더 많은 정당화 / 설명이 필요합니다. 무엇에 AggregateObject추가 KeyValuePair합니까? 질문에서 요청한 "반복"은 어디에 있습니까?
Marc L.

선택은 사전을 반복하고 각 객체에 대해 작업 할 수있게합니다. 만큼 일반적인 것은 foreach아니지만 많이 사용했습니다. 내 대답은 진정으로 공감할 가치가 있는가?
Pixar

아니요, 반복을 Select 사용 하여 결과에 영향을 주지만 반복자 자체는 아닙니다. 반복 ( foreach), 특히 부작용이있는 작업에 사용되는 작업 유형은을 포함하여 Linq의 범위를 벗어납니다 Select. 람다 aggregateObjectCollection는 실제로 열거 될 때까지 실행되지 않습니다 . 이 답변을 "첫 번째 경로"(즉, 직선 앞에 사용 foreach)로 사용하면 나쁜 관행을 장려합니다. 상황에 따라 사전을 반복 하기 전에 도움이 되지만 요청한대로 질문을 해결하지 못하는 Linq 작업이있을 수 있습니다 .
Marc L.

0

Dictionary <TKey, TValue> c #의 제네릭 컬렉션 클래스이며 데이터를 키 값 형식으로 저장합니다 .Key는 고유해야하며 null 일 수없는 반면 값은 중복되고 null 일 수 있습니다. 키와 그 값을 나타내는 KeyValuePair <TKey, TValue> 구조로 처리됩니다. 따라서 요소 반복 중에 KeyValuePair <TKey, TValue> 요소 유형을 가져와야합니다. 아래는 예입니다.

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");

foreach (KeyValuePair<int, string> item in dict)
{
    Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}

0

for 루프를 사용하려면 다음을 수행하십시오.

var keyList=new List<string>(dictionary.Keys);
for (int i = 0; i < keyList.Count; i++)
{
   var key= keyList[i];
   var value = dictionary[key];
 }

그래도 이것의 장점은 무엇입니까? 그것은보다 긴 코드의 foreach루프 있기 때문에 더 나쁜 성능을 new List<string>(dictionary.Keys)반복 할 것이다 dictionary.Count당신도 스스로 반복하는 기회를하기 전에 시간을. "가장 좋은 방법"을 요구하는 것은 주관적이라는 점을 제외하고는 이것이 질문이 찾는 "가장 좋은 방법"또는 "표준 방법"으로 어떤 자격이 있는지는 알 수 없습니다. "당신은 루프에 사용하려는 경우 ..."에 내가 함께 카운터 것 " 하지 마십시오 용도 for루프를."
BACON

컬렉션이 많고 작업 속도가 느리고 반복 할 때 컬렉션이 변경 될 수있는 경우 "컬렉션이 변경되었습니다"오류로부터 보호하고이 솔루션의 성능은 ElementAt보다 우수합니다.
Seçkin Durgay

"컬렉션이 수정되었습니다"예외를 피하는 것이 한 가지 이유인데, 그 특별한 경우는 질문에 명시되어 있지 않으며 항상 할 수는 foreach (var pair in dictionary.ToArray()) { }있습니다. 아직도, 나는이 코드를 사용하려는 특정 시나리오와 그 의미를 명확하게 이해하는 것이 좋을 것이라고 생각합니다.
BACON

네 당신 말이 맞지만 ElementAt에 대한 답변이 여기 있으며 매우 높은 명성을 얻었
으며이

-1

linq로 간단

 Dictionary<int, string> dict = new Dictionary<int, string>();
 dict.Add(1, "American Ipa");
 dict.Add(2, "Weiss");
 dict.ToList().ForEach(x => Console.WriteLine($"key: {x.Key} | value: {x.Value}") );

클래스 에만 정의되어 ToList()있기 때문에 전화하는 것을 알지만 왜 그 대신에 모든 것을 수행 합니까? 나는 그것이 훨씬 간단하고 동일한 메모리 / 성능 관련성을 가지고 있지 않다고 말하고 싶습니다. 이 정확한 해결책은 어쨌든 3.5 년 전부터이 답변 에서 이미 제안되었습니다 . ForEach()List<>foreach (var pair in dict) { }
BACON

단지 코드 시각화를 위해, 그것은 당신이 지시 한 방식으로 실제로 수행 될 수 있습니다. 나는 단지 그것을 다른 방식으로 제시하고 싶었습니다. 그리고 더 희박한 견해로, 대답이 표시되지 않은 것에 대해 사과하지 않습니다. 포옹
Luiz Fernando Corrêa Leite

-3

사용 사이에 토론이있는 최고 순위 게시물 외에도

foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

또는

foreach(var entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

초기화에서 사전 유형을 볼 수 있기 때문에 가장 완전한 것은 다음과 같습니다. kvp는 KeyValuePair입니다.

var myDictionary = new Dictionary<string, string>(x);//fill dictionary with x

foreach(var kvp in myDictionary)//iterate over dictionary
{
    // do something with kvp.Value or kvp.Key
}

5
두 번째 사전을 작성하고 복사하는 것은 코드 가독성에 대한 올바른 솔루션이 아닙니다. 사실, 나는 "마지막 사람이 왜 두 번째 사전을 만들었 을까?"라고 스스로에게 물어봐야하기 때문에 코드를 이해하기 어렵게 만들 것이라고 주장합니다. 좀 더 장황하게하려면 옵션 1 만 사용하십시오.
Matthew Goulart

나는 단지 각각에 대한 선언이있을 때 foreach의 사용법이 선언에서 명확하다는 것을 보여 주려고했다
BigChief
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.