Swift: вложенный словарь удалить все соответствующие ключи - PullRequest
0 голосов
/ 12 ноября 2018

Мне нужно расширение словаря, которое может удалить все соответствующие ключи из произвольного словаря ([String: Any]).

Пример использования может выглядеть следующим образом:

Удалить все ключи из данного словаря, которые соответствуют одному из следующих: ["test", "staging"]

[
"foo":  [ "bar": "tralala" ]
"test": [ "foo": "bar", "staging": "hi"]
"aaa":  [ "bbb": "cccc", "staging": "jjj"]
]

Ожидаемый результат:

[
"foo": [ "bar": "tralala" ]
"aaa":  [ "bbb": "cccc"]
]

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

Использование Any в качестве типа для значений словаря не рекомендуется. В этом случае было бы предпочтительнее определить ваш словарь как [String : [String : String]].

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

let dictionary = [
    "foo" : [ "bar": "tralala" ],
    "test": [ "foo": "bar", "staging": "hi"],
    "aaa" : [ "bbb": "cccc", "staging": "jjj"],
    "d"   : [ "e": "f", "g": ["h": "i", "test": "j"]],
]

И объявите ключи, которые мы хотели бы удалить:

let badKeys = ["test", "staging"]

Вот рекурсивная функция, которая удаляет ненужные ключи:

func remove(_ keys: [String], from dict: [String: Any]) -> [String: Any] {
    var filtered = dict.filter { !keys.contains($0.key) }
    for entry in filtered {
        if let value = entry.value as? [String : String] {
            filtered[entry.key] = remove(badKeys, from: value)
        }
    }
    return filtered
}

И вы можете использовать это так:

let result = remove(badKeys, from: dictionary)

Что дает:

["aaa": ["bbb": "cccc"], "foo": ["bar": "tralala"], "d": ["e": "f", "g": [ "h": "i"]]]

(Имейте в виду, что словарь представляет собой неупорядоченную коллекцию, поэтому результаты могут отличаться по порядку)

0 голосов
/ 12 ноября 2018

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

Однако, давайте посмотрим, сможем ли мы помочь.Вы заявляете, что ваш словарь имеет тип [String:Any] и не указываете лимит вложенности, поэтому мы будем использовать следующие тестовые данные:

let sampleDict : [String:Any] =
[
   "foo":  [ "bar": "tralala" ],
   "test": [ "foo": "bar", "staging": "hi"],
   "staging" : 3,
   "one" : [ "two" : [ "three" : 3, "staging" : 4.2]],
   "aaa":  [ "bbb": "cccc", "staging": "jjj"]
]

Если наш алгоритм справится с этим, он должен справиться с чем угодно (известныйпоследние слова ...).

Простой алгоритм, использующий предопределенные методы и избегающий циклов:

  1. Фильтрует словарь, удаляя любые пары ключ / значение, где ключ должен быть удален.
  2. Сопоставить значения в отфильтрованном словаре для любого значения, которое само является словарем [String:Any], рекурсивно применить этот алгоритм к значению.

В Swift:

func removeMatchingKeys(_ dict : [String:Any], _ keysToRemove : [String]) -> [String:Any]
{
   return dict
      // filter keeping only those key/value pairs
      // where the key isn't in keysToRemove
      .filter { !keysToRemove.contains($0.key) }
      // map the values in the filtered dictionary recursing
      // if the value is itself a [String:Any] dictionary
      .mapValues
      {  if let nested = $0 as? [String:Any]
         // value is dictionary, recurse
         { return removeMatchingKeys(nested, keysToRemove) }
         else
         // value isn't a dictionary, leave as is
         { return $0 }
      }
}

Проверка этого с помощью ключей:

let sampleKeys = ["test", "staging"]

Оператор:

print( removeMatchingKeys(sampleDict, sampleKeys) )

Производит:

["foo": ["bar": "tralala"], "aaa": ["bbb": "cccc"], "one": ["two": ["three": 3.0]]]

Приведенный выше алгоритм выполняет два проходаданные, сначала отфильтровать его, а затем сопоставить его.Если и только если , это оказывается проблемой производительности, вы можете заменить две предопределенные функции filter и map простым рукописным циклом, который объединяет операции и передает только черезданные один раз.

Примечание. Выше используется Xcode 10 / Swift 4.2, используйте любую другую версию и YMMV (т. е. синтаксис и предварительно определенные функции могут легко отличаться), но алгоритм все еще применим.

...