Вставка значения в список значений ключа в словаре

1

У меня есть rowsDictionary что его ключи указывают на список классов EmployeeSummary. В этих классах EmployeeSummary у нас также есть строковое свойство Delivery_System

Я прохожу через это таким образом, но теперь застрял в той части, в которой я хочу иметь deliverySystemFinder dictioanry что ее ключи combinedKey как deliverySystemFinder dictioanry ниже, а значение для каждого ключа - это список различных значений delivery_system

//rowsDictionary is a Dictionary<string, List<EmployeeSummary>>

Dictionary<string, List<string>> deliverySystemFinder = new Dictionary<string, List<string>>();

foreach (string key in rowsDictionary.Keys)
{
    List<EmployeeSummary> empList = rowsDictionary[key];
    foreach (EmployeeSummary emp in empList)
    {
        string combinedKey = emp.LastName.Trim().ToUpper() + emp.FirstName.Trim().ToUpper();
        string delivery_system = emp.Delivery_System;
        // so now I should go and 
        //A) does deliverySystemFinder have this combinedKey? if not add it. 
        //B) Does combinedKey in the list of its values already have the value for delivery_system? if it does not then add it 
    }
}
Теги:

1 ответ

4
Лучший ответ

Это будет работать, для начала:

foreach (string key in rowsDictionary.Keys)
{
    List<EmployeeSummary> empList = rowsDictionary[key];
    foreach (EmployeeSummary emp in empList)
    {
        string combinedKey = emp.LastName.Trim().ToUpper() +
            emp.FirstName.Trim().ToUpper();

        string delivery_system = emp.Delivery_System;

        List<string> systems = null;

        // check if the dictionary contains the list
        if (!deliverySystemFinder.TryGetValue(combinedKey, out systems))
        {
            // if not, create it and add it 
            systems = new List<string>();
            deliverySystemFinder[combinedKey] = systems;
        }

        // check if the list contains the value and add it
        if (!systems.Contains(delivery_system))
            systems.Add(delivery_system);
    }
}

Теперь несколько замечаний:

  1. Не имеет смысла итерации через Keys, а затем выполнять поиск на каждой итерации. Вы можете напрямую перебирать KeyValuePair с помощью цикла foreach.

  2. Использование конкатенированных строк в качестве уникальных ключей часто терпит неудачу. В этом случае, что произойдет, если у вас есть пользователи { LastName="Some", FirstName="Body" } и { LastName="So", FirstName="Mebody" } в вашем списке?

  3. Проверка того, что List содержит значение, является операцией O(n). Вы бы значительно повысили производительность, если вместо этого использовали HashSet<string>.

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

// returns a Dictionary<EmployeeSummary, List<string>>
// which maps each distinct EmployeeSummary into a list of
// distinct delivery systems
var groupByEmployee = rowsDictionary
    .SelectMany(kvp => kvp.Value)
    .GroupBy(s => s, new EmployeeSummaryEqualityComparer())
    .ToDictionary(
         s => s.Key, 
         s => s.Select(x => x.Delivery_System).Distinct().ToList());

С EmployeeSummaryEqualityComparer определено что-то вроде:

class EmployeeSummaryEqualityComparer : IEqualityComparer<EmployeeSummary>
{
    public bool Equals(EmployeeSummary x, EmployeeSummary y)
    {
        if (object.ReferenceEquals(x, null))
            return object.ReferenceEquals(y, null);

        return 
            x.FirstName == y.FirstName &&
            x.LastName == y.LastName &&
            ... (depending on what constitutes 'equal' for you)
    }

    public int GetHashCode(EmployeeSummary x)
    {
        unchecked
        {
            var h = 31;   // null checks might not be necessary?
            h = h * 7 + (x.FirstName != null ? x.FirstName.GetHashCode() : 0);
            h = h * 7 + (x.LastName != null ? x.LastName.GetHashCode() : 0);
            ... other properties similarly ...
            return h;
        }
    }
}

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

// returns a Dictionary<string, List<string>>
var groupByEmployee = rowsDictionary
    .SelectMany(kvp => kvp.Value)
    .GroupBy(s => s.LastName.ToUpper() + s.FirstName.ToUpper())
    .ToDictionary(
         s => s.Key,
         s => s.Select(x => x.Delivery_System).Distinct().ToList());
  • 0
    Спасибо .. "для начала"? :) так есть ли более эффективный способ тоже? Мне действительно нужно быть осторожным с нехваткой памяти в этом коде, эти словари в нем похожи на 110 000 элементов
  • 0
    для вопроса 2: Да, в реальном коде у него также есть поле идентификатора, так что это комбинация из трех вещей, я просто опубликовал две из них здесь для краткости.
Показать ещё 8 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню