Am'm, folosind un Dicționar<string, int>unde
int` este un număr de cheie.
Acum, am nevoie pentru a accesa ultimul introdus Cheia în Dicționar, dar nu stiu numele. Evident încercare:
int LastCount = mydict[mydict.keys[mydict.keys.Count]];
nu funcționează, pentru că în Dicționarul.Tastele
nu pune în aplicare o []-indexer.
Mă întreb dacă nu există nici o clasă similară? M-am gândit folosind o Stivă, dar asta doar memorează un șir de caractere. Am putea crea acum propriile mele struct și de a folosi apoi un Teanc
Ca @Falanwe puncte într-un comentariu, face ceva de genul asta este incorectă:
int LastCount = mydict.Keys.ElementAt(mydict.Count -1);
Ai nu trebuie depinde de ordinea de chei într-un Dicționar. Dacă aveți nevoie de a comanda, ar trebui să utilizați un OrderedDictionary, așa cum este propusă în răspunde. Alte răspunsuri pe această pagină sunt interesante, la fel de bine.
Puteți utiliza un OrderedDictionary.
Reprezintă o colecție de cheie/valoare perechi care sunt accesibile prin cheia sau index.
Un Dicționar este un Tabel Hash, astfel încât aveți nici o idee despre ordinul de inserție!
Dacă vrei să știi, ultimul introdus cheia aș sugera extinderea Dicționar pentru a include un LastKeyInserted valoare.
E. g.:
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
}
Va rula în probleme cu toate acestea, atunci când utilizați .Elimina()
deci, pentru a depăși acest lucru, va trebui să păstreze o listă ordonată de cheile introdus.
De ce nu't ai prelungi dicționar class pentru a adăuga într-un ultim cheie introdus de proprietate. Ceva de genul următor poate?
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);
}
}
Ai putea întotdeauna face acest lucru:
string[] temp = new string[mydict.count];
mydict.Keys.CopyTo(temp, 0)
int LastCount = mydict[temp[mydict.count - 1]]
Dar nu't recomanda. Nu's nici o garanție că ultima introdus cheia va fi la sfârșitul șirului. Comanda pentru Chei pe MSDN este nespecificat, și sub rezerva de a schimba. În foarte scurt test, aceasta nu pare să fie în ordine de inserție, dar'd fi mai bine clădire corespunzătoare în contabilitate ca o stivă-cum ai sugerat (deși nu - 't vedea nevoie de un struct, bazate pe alte declarații)--sau singură variabilă cache-ul dacă aveți nevoie doar să știu de cele mai recente cheie.
Cred că puteți face ceva de genul asta, sintaxa ar putea fi greșit, n-a folosit C# într-un timp Pentru a ajunge la ultimul element
Dictionary<string, int>.KeyCollection keys = mydict.keys;
string lastKey = keys.Last();
sau de a folosi Max în loc de Trecut pentru a ajunge la valoarea maximă, nu stiu care se potriveste codul mai bine.
O alternativă ar fi un KeyedCollection în cazul în care cheia este încorporat în valoare.
Doar a crea o bază de implementare a sigilat într-o clasă de a utiliza.
Deci, pentru a înlocui în Dicționarul<string, int>
(care nu e't un foarte bun exemplu ca nu e't o cheie de clar pentru un 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];
Sunt de acord cu partea a doua de Patrick's a răspunde. Chiar dacă în unele teste se pare a ține de inserție comandă, documentația (și un comportament normal pentru dicționare și hash-uri) în mod explicit în comanda este nespecificat.
Te're lumânarea în funcție de comanda de chei. Adăugați propriile contabilitate (ca Patrick mi-a spus, doar o singură variabilă pentru ultima adăugat cheie) pentru a fi sigur. De asemenea, don't fi tentat de toate metodele cum ar fi Ultima și Max în dicționar ca acestea sunt, probabil, în ceea ce privește cheia de comparator (I'm nu sunt sigur de asta).
În cazul în care vă decideți să utilizați cod periculos, care este obiectul la rupere, această funcție de extensie va aduce o cheie de la un `Dicționar<K,V> potrivit spuselor sale interne de indexare (care pentru Mono și .NET în prezent pare să fie în aceeași ordine ca ai obține prin enumerarea "Cheilor" de proprietate).
Este de preferat a folosi Linq: dict.Tastele.ElementAt(i)
, dar că funcția se va repeta O(N); următoarele este O(1), dar cu o reflecție penalizare de performanță.
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);
}
};
Felul în care ai formulat întrebarea mă face să cred că int în Dicționarul conține elementul's "poziția" în Dicționar. Judecând după afirmația că tastele sunt't stocate în ordinea în care au're adăugată, dacă aceasta este corectă, ar însemna că cheile.Count (sau .Count - 1, daca're folosind zero-based) ar trebui totuși să fie întotdeauna numărul de ultimul-intrat-cheie?
Dacă asta's corecte, nu există nici un motiv să puteți't folosi în loc de Dicționar<int, string> astfel încât să puteți utiliza mydict[ mydict.Tastele.Conta ]?
Eu nu't știu dacă acest lucru ar funcționa pentru că m-am'm destul de sigur că tastele sunt't stocate în ordinea în care acestea sunt adăugate, dar ai putea arunca KeysCollection la o Listă
Singurul lucru la care mă pot gândi este de a stoca cheile într-o listă de căutare și se adaugă cheile de la lista înainte de a le adăuga la dicționar... l's nu destul tho.
Pentru a extinde pe Daniels post și comentarii cu privire la cheie, din moment ce cheia este încorporat în valoarea oricum, ai putea recurge la utilizarea unui KeyValuePair<TKey, TValue>` ca valoare. Principalul argument pentru aceasta este faptul că, în general, Cheia e't neapărat direct decurg din valoare.
Apoi se'd arata astfel:
public sealed class CustomDictionary<TKey, TValue>
: KeyedCollection<TKey, KeyValuePair<TKey, TValue>>
{
protected override TKey GetKeyForItem(KeyValuePair<TKey, TValue> item)
{
return item.Key;
}
}
Pentru a folosi acest lucru ca în exemplul anterior, ar'd face:
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;
Puteți folosi, de asemenea, Motorola și omologul său Generic. Aceste două clase și în Andrew Peters răspunsul menționat OrderedDictionary dicționar sunt clase în care elementele pot fi accesate prin index (pozitie), precum și de cheie. Cum să utilizați aceste cursuri puteți găsi: Motorola Clasa , Motorola Clasă Generică .
Visual Studio's UserVoice dă un link la generic OrderedDictionary implementation de dotmore.
Dar dacă aveți nevoie doar pentru a obține perechi cheie/valoare de index și don't nevoie pentru a obține valorile de taste, puteți folosi un truc simplu. Declara unele clasă generică (l-am numit ListArray), după cum urmează:
class ListArray<T> : List<T[]> { }
Puteți, de asemenea, să declare, cu constructori:
class ListArray<T> : List<T[]>
{
public ListArray() : base() { }
public ListArray(int capacity) : base(capacity) { }
}
De exemplu, ai citit unele perechi cheie/valoare dintr-un fișier și doriți doar pentru a le stoca în ordinea în care au fost citite astfel încât pentru a obține-le mai târziu de index:
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];
Așa cum poate ați observat, puteți avea nu neapărat doar de perechi cheie/valoare în ListArray. Elementul de matrice poate fi de orice lungime, ca în zimțate matrice.