Отфильтруйте все элементы Dictionary, которые соответствуют только массиву входных строк или любому числу - PullRequest
0 голосов
/ 04 января 2019

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

Цель состоит в том, чтобы прочитать список значений для свойства из сплющенного объекта.

Пример словаря:

Key: "Owner.0.Alias", Value: "Jo"
Key: "Owner.0.Name", Value: "John"
Key: "Owner.0.ReportsTo.Alias", Value: "Sam"
Key: "Owner.0.ReportsTo.Name", Value: "Samantha"    
Key: "Owner.1.Alias", Value: "Ma"
Key: "Owner.1.Name", Value: "Mary"
Key: "Owner.1.ReportsTo.Alias", Value: "Geo"
Key: "Owner.1.ReportsTo.Name", Value: "George"    
Key: "Manager.Alias", Value:"Ke"
Key: "Manager.Name", Value:"Ken"

входной массив -

string str = Owners.Alias;
var subStringArr = str.Split('.');

**Input array will have** : [0]: Owners, [1]:Alias

Я бы хотел отфильтровать все элементы словаря, имеющие ключевые слова "Владельцы" / "Псевдоним" / "Число" из приведенного выше списка.

**Expected output: **
Key: Owner.0.Alias, Value: Jo
Key: Owner.1.Alias, Value: Ma

Обратите внимание: уровень иерархии ключа словаря может быть любым длинным. Уровень не известен.

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

1 Ответ

0 голосов
/ 04 января 2019

Вы можете сделать следующее. Я разбил запрос на подзапрос для удобства чтения.

var intial = dictionary.Keys.Select(c=> c.Split('.'));
var intermediate = intial.Where(x=>x
                            .Except(subStringArr)
                            .All(c=>Regex.IsMatch(c, @"^\d+$")));

var result =  intermediate.Select(x=> new KeyValuePair<string,string>(string.Join(".",x), dictionary[string.Join(".",x)]))
                        .ToDictionary(x=>x.Key, y=>y.Value);

Для ввода

var dictionary = new Dictionary<string,string>{
["Owner.0.Alias"] = "Jo",
["Owner.0.Name"] = "John",
["Owner.0.ReportsTo.Alias"] = "Sam",
["Owner.0.ReportsTo.Name"] = "Samantha",
["Owner.1.Alias"] = "Ma",
["Owner.1.Name"] = "Mary",
["Owner.1.ReportsTo.Alias"] = "Geo",
["Owner.1.ReportsTo.Name"] = "George",
["Manager.Alias"] = "Ke",
["Manager.Name"] = "Ken",
};

string str = "Owner.Alias";
var subStringArr = str.Split('.');

Вы получите вывод как

Key: Owner.0.Alias, Value: Jo
Key: Owner.1.Alias, Value: Ma

Общая идея:

  1. Разделение клавиш с использованием «.» в массив
  2. Убедитесь, что subStringArray является подмножеством массива на шаге 1
  3. Убедитесь, что любым оставшимся элементом успешного совпадения подмножества в Шаге 2 является число
  4. Форма Окончательный результат

Обновление (на основе комментариев)

Чтобы обеспечить достижение результата, даже когда входной массив больше, чем длина ключа словаря, например ("Persona.Requestor.Owner.ReportsTo.Name"), вы можете изменить промежуточный запрос как

var intermediate = intial.Where(x=>  (subStringArr.Count() > x.Count()?
                                            subStringArr.Except(x)
                                           :x.Except(subStringArr))
                            .All(c=>Regex.IsMatch(c, @"^\d+$")));

Это поможет разобрать ключи как "Persona.0.Requestor.0.Owner.0.ReportsTo.Name".

...