Vra

Ek het 'n Dictionary<string, int> waar die int is 'n telling van die sleutel.

Nou, ek moet toegang tot die laaste ingevoeg Sleutel binne die woordeboek, maar nie die naam daarvan weet. Die voor die hand liggend poging:

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

nie werk nie, want Dictionary.Keys nie implementeer 'n [] -indexer.

Ek wonder net of daar enige soortgelyke klas? Ek het gedink oor die gebruik van 'n stapel, maar dat slegs slaan 'n string. Ek kon nou skep my eie struct en gebruik dan 'n Stack<MyStruct>, maar ek wonder of daar is 'n ander alternatief, in wese 'n woordeboek wat 'n [] -indexer op die sleutels implemente?

Was dit nuttig?

Oplossing

As @Falanwe wys daarop in 'n kommentaar, so iets te doen, is verkeerde :

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

Jy nie afhang van die orde van sleutels in 'n woordeboek. As jy bestel het, moet jy gebruik 'n OrderedDictionary , soos voorgestel in hierdie beantwoord . Die ander antwoorde op hierdie blad word interessant as well.

Ander wenke

Jy kan 'n OrderedDictionary gebruik.

  

verteenwoordig 'n versameling van die belangrikste / waarde   pare wat toeganklik is deur die sleutel is   of indeks.

'n woordeboek is 'n Hash Table, so jy het geen idee aan die orde van invoeging!

As jy wil die laaste ingevoeg sleutel Ek stel voor die uitbreiding van die woordeboek 'n LastKeyInserted waarde insluit. Weet

Bv:.

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

}

Jy sal in die moeilikheid is egter wanneer jy .Remove() so gebruik om dit te oorkom wat jy sal hê om 'n geordende lys van die sleutels ingevoeg hou.

Hoekom doen jy nie net uit te brei die woordeboek klas by te voeg in 'n laaste sleutel ingevoeg eiendom. Iets soos die volgende miskien?

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

Jy kan altyd dit te doen:

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

Maar ek sou dit nie aanbeveel nie. Daar is geen waarborg dat die laaste ingevoeg sleutel sal wees aan die einde van die skikking. Die bestel vir Keys op MSDN is ongespesifiseerde, en onderhewig aan verandering. In my baie kort toets, beteken dit blyk te wees ten einde van inplanting, maar jy sal beter daaraan toe gebou in behoorlike boekhouding soos 'n stapel wees - as jy voorstel (al het ek nie die behoefte van 'n struct gebaseer op sien jou ander state) - of 'n enkele veranderlike kas as jy net nodig het om die nuutste belangrike weet

.

Ek dink jy kan iets soos hierdie, die sintaksis dalk verkeerd wees nie, havent gebruik C # in 'n rukkie Om die laaste item te kry

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

of gebruik Max in plaas van laastes wees om die maksimum waarde te kry, ek weet nie watter een jou kode beter pas.

Een alternatief sou wees 'n KeyedCollection as die sleutel is ingesluit in die waarde.

skep Net 'n basiese implementering in 'n verseëlde klas te gebruik.

So om Dictionary<string, int> vervang (wat nie 'n baie goeie voorbeeld, want daar is nie 'n duidelike sleutel vir 'n 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];

Ek stem saam met die tweede deel van Patrick se antwoord. Selfs al in 'n paar toetse dit lyk vir invoeging orde, die dokumentasie (en normale gedrag vir woordeboeke en hashes) hou uitdruklik die bestel is ongespesifiseerde.

Jy is net te vra vir moeilikheid, afhangende van die bestel van die sleutels. Voeg jou eie boekhouding (soos Patrick gesê, net 'n enkele veranderlike vir die laaste bygevoeg sleutel) om seker te wees. Moet ook nie in die versoeking deur al die metodes soos Verlede en Max op die woordeboek as dit is waarskynlik in verband met die sleutel vergelyker (ek is nie seker oor wat).

In die geval dat jy besluit om gevaarlike kode wat onderworpe is aan skade gebruik, sal hierdie uitbreiding funksie 'n sleutel van 'n Dictionary<K,V> haal volgens sy interne kruip (wat vir Mono en NET op die oomblik blyk te wees in dieselfde volgorde as jy deur deelinventaris die eiendom Keys).

Dit is baie beter om te gebruik Linq: dict.Keys.ElementAt(i), maar daardie funksie sal herhaal O (N); die volgende is O (1), maar met 'n weerspieëling prestasie straf.

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

Die manier waarop jy die vraag bewoorde lei my om te glo dat die int in die woordeboek bevat "posisie" die item se op die woordeboek. Te oordeel aan die bewering dat die sleutels nie in die volgorde wat hulle bygevoeg gestoor word, indien dit korrek is, wat sou beteken dat keys.Count (of .Count - 1 As jy met behulp van nul-gebaseerde) moet nog altyd die getal van die laaste geloop sleutel wees?

As dit korrek is, is daar geen rede waarom jy kan nie plaas gebruik woordeboek sodat jy kan gebruik mydict [mydict.Keys.Count]?

Ek weet nie of dit sal werk nie, want ek is redelik seker dat die sleutels nie in die volgorde waarin hulle is bygevoeg gestoor, maar jy kan die KeysCollection werp om 'n lys en dan kry die laaste sleutel in die lys ... maar dit sal die moeite werd om 'n blik te wees.

Die enigste ander ding wat ek kan dink is om die sleutels in 'n lookup lys stoor en voeg die sleutels om die lys voordat jy dit by die woordeboek ... dit is nie mooi tho.

Om uit te brei op Daniels post en sy kommentaar oor die sleutel, want die sleutel binne die waarde in elk geval is ingesluit, kan jy terugval op die gebruik van 'n KeyValuePair<TKey, TValue> as die waarde. Die belangrikste rede hiervoor is dat, in die algemeen, die sleutel is nie noodwendig direk afleidbaar uit die waarde.

Toe dit wil lyk:

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

Om dit te gebruik as in die vorige voorbeeld, sou jy doen:

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;

Jy kan ook SortedList en sy generiese eweknie gebruik. Hierdie twee klasse en in Andrew Peters antwoord genoem OrderedDictionary is woordeboek klasse waarin items kan verkry word deur die indeks (posisie) asook deur sleutel. Hoe om hierdie klasse gebruik wat jy kan vind: SortedList Klas , SortedList Generiese klas .

'n woordeboek kan nie baie intuïtief vir die gebruik van die indeks vir verwysing wees, maar jy kan soortgelyke operasies het met 'n verskeidenheid van KeyValuePair :

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

Visual Studio se UserVoice gee 'n skakel na generiese OrderedDictionary implementering deur dotmore.

As jy net nodig het om die sleutel / waarde pare te kry deur die indeks en hoef nie waardes kry deur sleutels, jy kan 'n eenvoudige truuk gebruik. Verklaar sommige generiese klas (ek noem dit ListArray) soos volg:

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

Jy kan ook verklaar dit met konstruktors:

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

Byvoorbeeld, lees jy 'n paar belangrike / waarde pare van 'n lêer en net wil om dit te stoor in die volgorde waarin hulle is so lees om hulle later te kry deur indeks:

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

As jy dalk opgemerk het, kan jy nie noodwendig net pare van sleutel / waarde het in jou ListArray. Die item skikkings kan van enige lengte wees, soos in kronkelende skikking.

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top