2012-01-25 17 views
7

Quiero una lista indexada por ID, ordenada por un atributo especial dentro de mi clase.SortedList indexado por otra cosa que no sea la clave

SortedList, no logra hacer esto, porque me obliga a ordenar por la clave ...

permite decir mi clase es

class example{ 
int Id; 
int Order 
} 

¿Hay alguna estructura que está indexado como un diccionario, y ordenado por otra cosa?

para que pueda acceder a los datos de identificación, pero en un foreach los datos se ordena por orden

Respuesta

2

Por lo que yo sé, no hay ningún objeto Dictionary tipo que le dará ese comportamiento a la derecha de la caja.

Si solo está preocupado por acceder en un orden específico en un bucle foreach, ¿por qué no utilizar LINQ?

SortedList<int, example> sortedList = new SortedList<int, example>(); 
... //populate list 

var sortedByOrder = from kp in sortedList 
        orderby kp.Value.Order 
        select kp; 

foreach (var kp in sortedByOrder) 
{ 
    ... //access will be ordered by example.Order 
} 

Sí tendrá que pagar una penalización en el rendimiento, pero si no es un problema esto es, en mi humilde opinión, la forma más fácil de obtener lo que desea.

+0

ya que sólo agregar los elementos de una vez, se utiliza la solución de – RagnaRock

2

yo sepa no hay nada previsto como estándar que proporcionará el pedido basado en valores, pero todavía proporcionan O (1) de búsqueda como un diccionario. Sin embargo escribir algo que puede hacer esto es bastante simple:

public class SortedLookup<TKey, TValue> : IEnumerable<TValue> 
{ 
    private readonly Dictionary<TKey, TValue> _lookup; 
    private readonly IComparer<TValue> _comparer; 

    public SortedLookup(IComparer<TValue> comparer) 
    { 
    _lookup = new Dictionary<TKey, TValue>(); 
    _comparer = comparer; 
    } 

    public TValue this[TKey key] 
    { 
    get { return _lookup[key]; } 
    set { _lookup[key] = value; } 
    } 

    public IEnumerator<TValue> GetEnumerator() 
    { 
    return _lookup.Values.OrderBy(v => v, _comparer).GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
    return GetEnumerator(); 
    } 
} 
2

Si la colección debe solicitarse en cualquier momento, una solución híbrida puede consistir en una colección ordenada y un diccionario.

Mi solución solo implementa ICollection<TValue>, pero es posible que desee implementar otras interfaces o métodos individuales también.

public class SortedKeydCollection<TKey, TOrder, TValue> : ICollection<TValue> 
{ 
    private Dictionary<TKey, TValue> _dict = new Dictionary<TKey, TValue>(); 
    private SortedList<TOrder, TValue> _list = new SortedList<TOrder, TValue>(); 
    Func<TValue, TKey> _keySelector; 
    Func<TValue, TOrder> _orderSelector; 

    public SortedKeydCollection(Func<TValue, TKey> keySelector, Func<TValue, TOrder> orderSelector) 
    { 
     _keySelector = keySelector; 
     _orderSelector = orderSelector; 
    } 

    #region ICollection<TValue> Members 

    public void Add(TValue item) 
    { 
     _dict[_keySelector(item)] = item; 
     _list[_orderSelector(item)] = item; 
    } 

    public void Clear() 
    { 
     _dict.Clear(); 
     _list.Clear(); 
    } 

    public bool Contains(TValue item) 
    { 
     return _dict.ContainsKey(_keySelector(item)); 
    } 

    public void CopyTo(TValue[] array, int arrayIndex) 
    { 
     int i = arrayIndex; 
     foreach (TValue item in _list.Values) { 
      if (i >= array.Length) { 
       break; 
      } 
      array[i++] = item; 
     } 
    } 

    public int Count 
    { 
     get { return _list.Count; } 
    } 

    public bool IsReadOnly 
    { 
     get 
     { 
      return ((ICollection<KeyValuePair<TOrder, TValue>>)_list).IsReadOnly || 
        ((ICollection<KeyValuePair<TKey, TValue>>)_dict).IsReadOnly; 
     } 
    } 

    public bool Remove(TValue item) 
    { 
     bool res1 = _list.Remove(_orderSelector(item)); 
     bool res2 = _dict.Remove(_keySelector(item)); 
     return res1 && res2; 
    } 

    #endregion 

    #region IEnumerable<TValue> Members 

    public IEnumerator<TValue> GetEnumerator() 
    { 
     return _list.Values.GetEnumerator(); 
    } 

    #endregion 

    #region IEnumerable Members 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return _list.Values.GetEnumerator(); 
    } 

    #endregion 
} 

Tenga en cuenta que los selectores de llave y el orden tienen que ser especificada en el constructor

var collection = new SortedKeydCollection<int, int, example>(x => x.Id, x => x.Order); 
Cuestiones relacionadas