Словарь с двумя клавишами?

Я отслеживаю значения в консоли. Два человека "дуэли" друг против друга, и я использовал словарь, чтобы сохранить имена, записанные вместе с нанесенным ущербом.

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

Я пытаюсь сохранить обоих пользователей в одной строке словаря, так что это можно проверить, так как User1 дует против User2. Таким образом, если начнется другая дуэль, это не будет мешать User1 или User2.

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

Мне нужны два ключа, поэтому я могу проверить, куда пойдет пользовательский урон. Урон всегда будет идти на другой ключ - наоборот. Что я могу сделать, чтобы сделать эту работу?

Спасибо.

Ответ 1

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
}

Сделайте несколько поединков. CreateSetComparer позволяет словарю использовать значения набора для тестирования равенства.

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

И найти поединок:

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

Ответ 2

Что-то быстрое.

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

Хотя правильное решение, на мой взгляд, будет использовать более продуманный объект UserScores, который отслеживает эту конкретную сессию "поединка".

Ответ 3

Вы можете попробовать создать пользовательский тип данных для ключа:

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

Затем используйте Dictionary<DualKey<string>, string>;

Ответ 4

Поскольку один человек может участвовать не более чем в одной поединке за раз, вы можете использовать один словарь для прямого "индексации" обеих конечных точек во всех дуэлях, что-то вроде этого:

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 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 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...

    }

}

Это всего лишь базовая идея, вы можете рассмотреть возможность включения этой функции в свой собственный класс...