2012-02-27 16 views
10

Estoy haciendo un seguimiento de los valores en una consola. Dos personas "se peleaban" una contra la otra y yo estaba usando un diccionario para mantener los nombres registrados junto con el daño hecho.Diccionario con dos teclas?

var duels = new Dictionary<string, string>(); 
duels.Add("User1", "50"); 
duels.Add("User2","34"); 

Estoy tratando de almacenar tanto los usuarios en la misma fila diccionario, así que podría ser verificado como Usuario1 es un duelo contra User2. De esta forma, si se iniciara otro duelo, no interferiría con User1 o User2.

duels.Add("KeyUser1","KeyUser2","50","34",.../*Other attributes of the duel*/); 

Necesito dos llaves para poder verificar a dónde irá el daño del usuario. El daño siempre irá a la otra tecla, viceversa. ¿Qué puedo hacer para que esto funcione?

Gracias.

+7

Recomendaría usar tuplas para esto. Aquí hay un artículo relacionado que puede llevarlo en la dirección correcta: http://stackoverflow.com/questions/1171812/multi-key-dictionary-in-c. ¡Buena suerte! – SMT

+0

¿Puede un solo usuario participar en más de un duelo a la vez? –

+0

¿El duelo entre "Usuario1" y "Usuario2" es diferente del duelo entre "Usuario2" y "Usuario1"? –

Respuesta

4
public class Duel 
{ 
    public string User1 {get; protected set;} 
    public string User2 {get; protected set;} 
    public Duel(string user1, string user2) 
    { 
    User1 = user1; 
    User2 = user2; 
    } 

    public HashSet<string> GetUserSet() 
    { 
    HashSet<string> result = new HashSet<string>(); 
    result.Add(this.User1); 
    result.Add(this.User2); 
    return result; 
    } 

    //TODO ... more impl 
} 

Hagamos algunos duelos. CreateSetComparer permite que el diccionario use los valores del conjunto para pruebas de igualdad.

List<Duel> duelSource = GetDuels(); 
Dictionary<HashSet<string>, Duel> duels = 
    new Dictionary<HashSet<string>, Duel>(HashSet<string>.CreateSetComparer()); 

foreach(Duel d in duelSource) 
{ 
    duels.Add(d.GetUserSet(), d); 
} 

Y encontrar un duelo:

HashSet<string> key = new HashSet<string>(); 
key.Add("User1"); 
key.Add("User2"); 
Duel myDuel = duels[key]; 
3

Usted podría intentar hacer un tipo de datos personalizado para la clave:

class DualKey<T> : IEquatable<DualKey<T>> where T : IEquatable<T> 
{ 
    public T Key0 { get; set; } 
    public T Key1 { get; set; } 

    public DualKey(T key0, T key1) 
    { 
     Key0 = key0; 
     Key1 = key1; 
    } 

    public override int GetHashCode() 
    { 
     return Key0.GetHashCode()^Key1.GetHashCode(); 
    } 

    public bool Equals(DualKey<T> obj) 
    { 
     return (this.Key0.Equals(obj.Key0) && this.Key1.Equals(obj.Key1)) 
      || (this.Key0.Equals(obj.Key1) && this.Key0.Equals(obj.Key0)); 
    } 
} 

luego usar un Dictionary<DualKey<string>, string>;

+1

No quiero sonar grosero, pero según la norma Stack Overflow esto debería ser un comentario sobre la pregunta original y no debe enviarse como respuesta. No quisiera que baje la votación :) – SMT

+1

No he probado un diccionario incrustado. Sin embargo, eso no significaría tener diferentes diccionarios clave? – Kyle

+1

@Tetreault Ah, tienes razón :(Mi error ... – Daryl

4

Algo rápido.

class UserScores { 

    public string Key { get; set; } 

    public int User1Score { get; set; } 
    public int User2Score { get; set; } 

    public UserScores(string username1, string username2) 
    { 
      Key = username1 + ":" + username2; 
    } 
} 

void Main() 
{ 
    var userScore = new UserScores("fooUser", "barUser"); 

    var scores = new Dictionary<string, UserScores>(); 

    scores.Add(userScore.Key, userScore); 

    // Or use a list 

    var list = new List<UserScores>(); 

    list.Add(userScore); 

    list.Single (l => l.Key == userScore.Key); 
} 

Aunque una solución adecuada en mi opinión sería utilizar un objeto UserScores mejor pensado que rastrea esa sesión "duelo" en particular.

+1

¿Qué pasa si 'vin' y' yetish' están peleando mientras 'vininy' y' etish' están peleando? :) –

+0

Me gusta la idea de combinarlos juntos.Creo que podría agregar algo así como 'username1 +': "+ username2 'y dividir el': 'para obtener' user [0] 'y' user [1] '. – Kyle

+0

Gracias @PaulBellora, respuesta actualizada. –

2

Dado que una sola persona puede estar involucrada en a lo sumo un duelo a la vez, se puede utilizar un único diccionario de forma directa "índice" ambos extremos en todos los duelos, algo como esto:

class Duel { 

    public Duel(string user1, string user2) { 
     Debug.Assert(user1 != user2); 
     User1 = user1; 
     User2 = user2; 
    } 

    public readonly string User1; 
    public readonly string User2; 
    public int User1Score; 
    public int User2Score; 

} 

class Program { 

    static void Main(string[] args) { 

     var dict = new Dictionary<string, Duel>(); 

     // Add a new duel. A single duel has two keys in the dictionary, one for each "endpoint". 
     var duel = new Duel("Jon", "Rob"); 
     dict.Add(duel.User1, duel); 
     dict.Add(duel.User2, duel); 

     // Find Jon's score, without knowing in advance whether Jon is User1 or User2: 
     var jons_duel = dict["Jon"]; 
     if (jons_duel.User1 == "Jon") { 
      // Use jons_duel.User1Score. 
     } 
     else { 
      // Use jons_duel.User2Score. 
     } 

     // You can just as easily find Rob's score: 
     var robs_duel = dict["Rob"]; 
     if (robs_duel.User1 == "Rob") { 
      // Use robs_duel.User1Score. 
     } 
     else { 
      // Use robs_duel.User2Score. 
     } 

     // You are unsure whether Nick is currently duelling: 
     if (dict.ContainsKey("Nick")) { 
      // Yup! 
     } 
     else { 
      // Nope. 
     } 

     // If Jon tries to engage in another duel while still duelling Rob: 
     var duel2 = new Duel("Jon", "Nick"); 
     dict.Add(duel2.User1, duel); // Exception! Jon cannot be engaged in more than 1 duel at a time. 
     dict.Add(duel2.User2, duel); // NOTE: If exception happens here instead of above, don't forget remove User1 from the dictionary. 

     // Removing the duel requires removing both endpoints from the dictionary: 
     dict.Remove(jons_duel.User1); 
     dict.Remove(jons_duel.User2); 

     // Etc... 

    } 

} 

esto es sólo una idea básica, es posible que considere envolver esta funcionalidad en su propia clase ...

Cuestiones relacionadas