как установить число от 0 до увеличения 1,2,, … и т.д. для объединенного словаря

#c#

#c#

Вопрос:

У меня есть 2 словаря, где Number = 0 для всех элементов,

 var dict1 = new Dictionary<string, Test>
{
    { "Key1", new Test { Number = 0, Name = "Name1" } },
    { "Key2", new Test { Number = 0, Name = "Name2" } },
    { "Key3", new Test { Number = 0, Name = "Name3" } }
};

var dict2 = new Dictionary<string, Test>
{
    { "Key1", new Test { Number = 0, Name = "Name1" } },
    { "Key4", new Test { Number = 0, Name = "Name4" } }
};
  

Теперь, после устранения повторяющихся пар ключ / значение, в результате комбинированного словаря я хочу установить число = 1, 2, 3, … как это сделать?

 var combine = dict1.Union(dict2)
    .GroupBy(kvp => kvp.Key)
    .Select(grp => grp.First())
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
  

Комментарии:

1. combine[<SomeKey>].Number = <SomeNumber>;

2. мне нужно иметь для всего элемента

3. Действительно ли ключи имеют номер (Key1 …) или это был просто пример. Вы хотите установить Key1 в Number = 1 …?

4. » мне нужно иметь для всего элемента «. Конечно. Ничто не помешает вам выполнить итерацию по словарю (или ключам словаря) и задать номера для всех элементов. Сделать это было бы намного, намного проще, чем то, что потребовалось бы вам, чтобы придумать конструкцию Linq в вашем вопросе…

5. Словарь неупорядочен, поэтому нет гарантии, что Key1 получит число = 1. Если вы явно не укажете ключ.

Ответ №1:

Вы можете сделать

 var n = 0; 
  

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

 var newDict = dict2.Select(d => new Test { Number =   n, Name = d.Value[1].Name }).ToDictionary();
  

Или с помощью старого доброго цикла:

 foreach(var d in dict2)
{
    d.Value[0].Number = n  ;
}
  

Как предложено в комментарии. Если вы хотите начать с 0, используйте

 n  ;
  

если с 1, используйте

   n; 
  

Комментарии:

1. Хорошее использование Linq, но вам следует немного объяснить это для тех, кто может этого не понять. Также рассмотрите возможность выполнения n вместо n , поскольку он хочет, чтобы нумерация предположительно начиналась с 1 (или принимала n 1 в качестве начального значения)

Ответ №2:

Попробуйте это:

 int i = 0;
var combine = dict1.Union(dict2)
    .GroupBy(kvp => kvp.Key)
    .OrderBy(kvp => kvp.Key)
    .ToDictionary(kvp => kvp.Key, kvp => new Test() { Number =   i, Name = kvp.First().Value.Name });
  

Это должно дать вам это:

 { "Key1", new Test { Number = 1, Name = "Name1" } },
{ "Key2", new Test { Number = 2, Name = "Name2" } },
{ "Key3", new Test { Number = 3, Name = "Name3" } }
{ "Key4", new Test { Number = 4, Name = "Name4" } }
  

Ответ №3:

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

Вы могли бы рассмотреть возможность помещения всех словарей в список и перебора каждого элемента и помещения его в объединенный результирующий словарь. Если элемент уже существует в результате, увеличьте Number свойство.

Начальная настройка:

 public class Test
{
    public int Number { get; set; }
    public string Name { get; set; }
}

var dict1 = new Dictionary<string, Test>
{
    { "Key1", new Test { Number = 0, Name = "Name1" } },
    { "Key2", new Test { Number = 0, Name = "Name2" } },
    { "Key3", new Test { Number = 0, Name = "Name3" } }
};

var dict2 = new Dictionary<string, Test>
{
    { "Key1", new Test { Number = 0, Name = "Name1" } },
    { "Key4", new Test { Number = 0, Name = "Name4" } }
};

// Put the dictionaries you want to combine into one list: 
var all = new List<Dictionary<string, Test>>();
all.Add(dict1);
all.Add(dict2);

// Declare result dictionary
var combine = new Dictionary<string, Test>();
  

Настройка завершена, это основной цикл, который вы хотите:

 foreach (var dict in all)
{
    foreach (var kvp in dict)
    {
        if (combine.ContainsKey(kvp.Key))
        {
            combine[kvp.Key].Number  ;
        }
        else
        {
            combine.Add(kvp.Key, kvp.Value);
        }
    }
}
  

Интерактивный вывод оболочки:

 Dictionary<string, Submission#0.Test>(4) { 
    { "Key1", Submission#0.Test { Name="Name1", Number=1 } }, 
    { "Key2", Submission#0.Test { Name="Name2", Number=0 } }, 
    { "Key3", Submission#0.Test { Name="Name3", Number=0 } }, 
    { "Key4", Submission#0.Test { Name="Name4", Number=0 } } 
}
  

Ответ №4:

Существует перегрузка расширения Select, которое также предоставляет индекс (MSDN)

 var combine = dict1.Union(dict2)
    .GroupBy(kvp => kvp.Key)
    .Select((grp,index) => new { Key = grp.Key, Value = new Test { Number = index 1, Name = grp.First().Name}})
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
  

Ответ №5:

Вы можете перебирать ключи

 int n = 1;
foreach (string key in combine.Keys) {
   combine[key].Number = n  ;
}
  

Ключи возвращаются не по порядку. Если вы хотите пронумеровать их по порядку:

 int n = 1;
var orderedKeyValuePairs = combine
    .OrderBy(kvp => kvp.Key, StringComparer.CurrentCultureIgnoreCase);
foreach (var kvp in orderedKeyValuePairs) {
    kvp.Value.Number = n  ;
}
  

Обратите внимание, что вы можете получить доступ к Number подобным образом, только если Test это ссылочный тип ( class ). Если Test было struct , вам пришлось бы переназначить всю структуру, потому что словарь вернул бы копию значения.

Необязательный StringComparer аргумент позволяет указать различные режимы сравнения строк:

 Ordinal, OrdinalIgnoreCase, CurrentCulture, CurrentCultureIgnoreCase
  

Если вы хотите отсортировать по имени:

 int n = 1;
var orderedValues = combine.Values
    .OrderBy(v => v.Name, StringComparer.CurrentCultureIgnoreCase);
foreach (var v in orderedValues) {
    v.Number = n  ;
}
  

Перебор пар ключ-значение или значений также имеет то преимущество, что вы можете изменять значение напрямую, тогда как при переборе ключей (как в моем первом фрагменте кода) вы должны искать словарь, что менее производительно.

Комментарии:

1. dict1[key].Number = n ; Я полагаю, что он просит нет?

2. Но ключи — это строки… OrderBy Может не дать желаемого результата.

3. Ключи — это строки, значения — объекты типа Test {int Number, имя строки}