문제

나는 Dictionary<string, int> 어디에 int 키의 개수입니다.

이제 사전에 마지막으로 삽입된 키에 접근해야 하는데 이름을 모르겠습니다.명백한 시도:

int LastCount = mydict[mydict.keys[mydict.keys.Count]];

작동하지 않습니다. 왜냐하면 Dictionary.Keys []-인덱서를 구현하지 않습니다.

비슷한 수업이 있는지 궁금합니다.스택을 사용하려고 생각했지만 문자열만 저장합니다.이제 나만의 구조체를 만든 다음 Stack<MyStruct>, 그러나 키에 []-인덱서를 구현하는 사전과 같은 또 다른 대안이 있는지 궁금합니다.

도움이 되었습니까?

해결책

@Falanwe가 댓글에서 지적했듯이 이와 같은 작업을 수행하는 것은 잘못된:

int LastCount = mydict.Keys.ElementAt(mydict.Count -1);

해서는 안 된다 사전의 키 순서에 따라 달라집니다.주문이 필요하신 분들은 꼭 이용해주세요 주문사전, 이 제안에 따르면 답변.이 페이지의 다른 답변도 흥미롭습니다.

다른 팁

당신은 사용할 수 있습니다 주문사전.

키 또는 인덱스가 액세스 할 수있는 키/값 쌍 모음을 나타냅니다.

사전은 해시 테이블이므로 삽입 순서를 알 수 없습니다!

마지막으로 삽입된 키를 알고 싶다면 LastKeyInserted 값을 포함하도록 사전을 확장하는 것이 좋습니다.

예:

public MyDictionary<K, T> : IDictionary<K, T>
{
    private IDictionary<K, T> _InnerDictionary;

    public K LastInsertedKey { get; set; }

    public MyDictionary()
    {
        _InnerDictionary = new Dictionary<K, T>();
    }

    #region Implementation of IDictionary

    public void Add(KeyValuePair<K, T> item)
    {
        _InnerDictionary.Add(item);
        LastInsertedKey = item.Key;

    }

    public void Add(K key, T value)
    {
        _InnerDictionary.Add(key, value);
        LastInsertedKey = key;
    }

    .... rest of IDictionary methods

    #endregion

}

그러나 사용하면 문제가 발생합니다 .Remove() 따라서 이 문제를 극복하려면 삽입된 키의 순서가 지정된 목록을 유지해야 합니다.

마지막 키 삽입 속성을 추가하기 위해 사전 클래스를 확장하는 것은 어떨까요?어쩌면 다음과 같은 것이 있을까요?

public class ExtendedDictionary : Dictionary<string, int>
{
    private int lastKeyInserted = -1;

    public int LastKeyInserted
    {
        get { return lastKeyInserted; }
        set { lastKeyInserted = value; }
    }

    public void AddNew(string s, int i)
    {
        lastKeyInserted = i;

        base.Add(s, i);
    }
}

언제든지 다음과 같이 할 수 있습니다.

string[] temp = new string[mydict.count];
mydict.Keys.CopyTo(temp, 0)
int LastCount = mydict[temp[mydict.count - 1]]

그러나 나는 그것을 추천하지 않을 것입니다.마지막으로 삽입된 키가 배열의 끝에 있다는 보장은 없습니다.열쇠 주문 MSDN에서 지정되지 않았으며 변경될 수 있습니다.아주 간단한 테스트에서는 삽입 순서인 것 같지만, 제안한 대로 스택과 같은 적절한 장부로 작성하는 것이 더 나을 것입니다. 다른 명령문)-또는 최신 키만 알아야 하는 경우 단일 변수 캐시입니다.

나는 당신이 이런 일을 할 수 있다고 생각합니다. 구문이 잘못되었을 수도 있고, 마지막 항목을 얻기 위해 C#을 사용하지 않았습니다.

Dictionary<string, int>.KeyCollection keys = mydict.keys;
string lastKey = keys.Last();

또는 Last 대신 Max를 사용하여 최대 값을 얻으려면 어느 것이 코드에 더 잘 맞는지 모르겠습니다.

한 가지 대안은 키 컬렉션 키가 값에 포함되어 있는 경우.

사용할 봉인 클래스에서 기본 구현을 생성하기만 하면 됩니다.

그래서 교체하려면 Dictionary<string, int> (int에 대한 명확한 키가 없기 때문에 이는 좋은 예가 아닙니다).

private sealed class IntDictionary : KeyedCollection<string, int>
{
    protected override string GetKeyForItem(int item)
    {
        // The example works better when the value contains the key. It falls down a bit for a dictionary of ints.
        return item.ToString();
    }
}

KeyedCollection<string, int> intCollection = new ClassThatContainsSealedImplementation.IntDictionary();

intCollection.Add(7);

int valueByIndex = intCollection[0];

나는 Patrick 답변의 두 번째 부분에 동의합니다.일부 테스트에서는 삽입 순서를 유지하는 것처럼 보이지만 문서(및 사전 및 해시의 일반적인 동작)에는 순서가 지정되지 않았다고 명시적으로 나와 있습니다.

키 순서에 따라 문제를 요청하는 것뿐입니다.확실하게 하려면 자신만의 장부를 추가하세요(Patrick이 말했듯이 마지막으로 추가된 키에 대한 단일 변수).또한 사전에 있는 Last 및 Max와 같은 모든 메소드에 유혹당하지 마십시오. 아마도 키 비교기와 관련되어 있을 것입니다(확실하지는 않습니다).

깨지기 쉬운 위험한 코드를 사용하기로 결정한 경우 이 확장 기능은 다음에서 키를 가져옵니다. Dictionary<K,V> 내부 인덱싱에 따르면(현재 Mono 및 .NET의 경우 Keys 재산).

Linq를 사용하는 것이 훨씬 바람직합니다. dict.Keys.ElementAt(i), 그러나 해당 함수는 O(N)을 반복합니다.다음은 O(1)이지만 반사 성능이 저하됩니다.

using System;
using System.Collections.Generic;
using System.Reflection;

public static class Extensions
{
    public static TKey KeyByIndex<TKey,TValue>(this Dictionary<TKey, TValue> dict, int idx)
    {
        Type type = typeof(Dictionary<TKey, TValue>);
        FieldInfo info = type.GetField("entries", BindingFlags.NonPublic | BindingFlags.Instance);
        if (info != null)
        {
            // .NET
            Object element = ((Array)info.GetValue(dict)).GetValue(idx);
            return (TKey)element.GetType().GetField("key", BindingFlags.Public | BindingFlags.Instance).GetValue(element);
        }
        // Mono:
        info = type.GetField("keySlots", BindingFlags.NonPublic | BindingFlags.Instance);
        return (TKey)((Array)info.GetValue(dict)).GetValue(idx);
    }
};

질문을 표현한 방식을 보면 사전의 int에 사전의 항목 "위치"가 포함되어 있다고 믿게 됩니다.키가 추가된 순서대로 저장되지 않는다는 주장으로 판단하면, 이것이 맞다면 key.Count (또는 0 기반을 사용하는 경우 .Count - 1)가 여전히 필요하다는 의미입니다. 항상 마지막에 입력한 키의 번호가 됩니까?

그것이 맞다면 mydict[ mydict.Keys.Count ]를 사용할 수 있도록 Dictionary<int, string>을 대신 사용할 수 없는 이유가 있습니까?

키가 추가된 순서대로 저장되지 않는다고 확신하기 때문에 이것이 작동할지는 모르겠지만 KeysCollection을 목록으로 캐스팅한 다음 목록의 마지막 키를 가져올 수 있습니다.하지만 한 번 볼만한 가치가 있을 것 같아요.

내가 생각할 수 있는 유일한 다른 방법은 키를 조회 목록에 저장하고 사전에 추가하기 전에 목록에 키를 추가하는 것입니다.그래도 안 예뻐요.

키에 관한 Daniels 게시물과 그의 의견을 확장하려면 키가 값에 내장되어 있으므로 다음을 사용할 수 있습니다. KeyValuePair<TKey, TValue> 값으로.이에 대한 주된 이유는 일반적으로 키가 반드시 값에서 직접 파생될 수는 없다는 것입니다.

그러면 다음과 같이 보일 것입니다:

public sealed class CustomDictionary<TKey, TValue>
  : KeyedCollection<TKey, KeyValuePair<TKey, TValue>>
{
  protected override TKey GetKeyForItem(KeyValuePair<TKey, TValue> item)
  {
    return item.Key;
  }
}

이전 예에서와 같이 이를 사용하려면 다음을 수행합니다.

CustomDictionary<string, int> custDict = new CustomDictionary<string, int>();

custDict.Add(new KeyValuePair<string, int>("key", 7));

int valueByIndex = custDict[0].Value;
int valueByKey = custDict["key"].Value;
string keyByIndex = custDict[0].Key;

SortedList와 해당 Generic 대응 항목을 사용할 수도 있습니다.이 두 클래스와 Andrew Peters의 답변에서 OrderedDictionary는 키뿐만 아니라 인덱스(위치)로 항목에 액세스할 수 있는 사전 클래스입니다.이러한 클래스를 사용하는 방법은 다음과 같습니다. SortedList 클래스 , SortedList 일반 클래스 .

사전은 참조용으로 인덱스를 사용하는 데 매우 직관적이지 않을 수 있지만, 배열을 사용하여 유사한 작업을 수행할 수 있습니다. 키값쌍:

전.KeyValuePair<string, string>[] filters;

비주얼 스튜디오의 사용자의 목소리 에 대한 링크를 제공합니다 일반 OrderedDictionary 구현 닷모어로.

그러나 인덱스별로 키/값 쌍만 가져오고 키별로 값을 가져올 필요가 없다면 간단한 방법을 사용할 수 있습니다.다음과 같이 몇 가지 일반 클래스(저는 ListArray라고 불렀습니다)를 선언합니다.

class ListArray<T> : List<T[]> { }

생성자를 사용하여 선언할 수도 있습니다.

class ListArray<T> : List<T[]>
{
    public ListArray() : base() { }
    public ListArray(int capacity) : base(capacity) { }
}

예를 들어, 파일에서 일부 키/값 쌍을 읽고 읽은 순서대로 저장하여 나중에 인덱스로 가져오려고 합니다.

ListArray<string> settingsRead = new ListArray<string>();
using (var sr = new StreamReader(myFile))
{
    string line;
    while ((line = sr.ReadLine()) != null)
    {
        string[] keyValueStrings = line.Split(separator);
        for (int i = 0; i < keyValueStrings.Length; i++)
            keyValueStrings[i] = keyValueStrings[i].Trim();
        settingsRead.Add(keyValueStrings);
    }
}
// Later you get your key/value strings simply by index
string[] myKeyValueStrings = settingsRead[index];

이미 알고 계시겠지만 ListArray에 키/값 쌍만 있을 필요는 없습니다.항목 배열은 들쭉날쭉한 배열처럼 길이에 제한이 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top