Фильтровать словарь с помощью вложенного словаря в Swift 5 - PullRequest
0 голосов
/ 29 сентября 2019

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

var Data: [Int : [String : String]] = [:]
var filteredData: [Int : [String : String]] = [:]
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text!)

//Don't know how to filter the nested dictionary, I can filter an array.
let array = (Data as NSArray).filtered(using: searchPredicate)
filteredData = array as! [String]

У кого-нибудь есть идеи относительно того, как мне подходить к этому?

Ответы [ 2 ]

1 голос
/ 30 сентября 2019

Во-первых, вам не нужно NSPredicate для такой простой задачи, String.contains() также должно работать.

Во-вторых, вы можете использовать комбинацию mapValues и compactMapValues для достиженияцель:

let searchQuery = "foo"
var data: [Int : [String : String]] = [:]
// map the values of the outer dictionary
let filteredData = data.mapValues {
    // we use compactMapValues on the inner dictionary as we want to exclude the values 
    // that don't match our search
    $0.compactMapValues { $0.contains(searchQuery) ? $0 : nil }
}

Если вы хотите еще больше уточнить поиск, например, чтобы не включать клавиши Int, которые не имеют совпадений во внутреннем словаре, вы можете compactMapValues навнешний словарь тоже:

let filteredData = data.compactMapValues {
    let filteredDict = $0.compactMapValues { $0.contains(searchQuery) ? $0 : nil }
    return filteredDict.isEmpty ? nil: filteredDict
}
1 голос
/ 29 сентября 2019

Чтобы дать вам несколько примеров, как фильтровать, я создал набор данных от победителя и призера в турнире Лиги чемпионов.В главном словаре клавиша Int соответствует году турнира.Словарь внутри имеет два ключа: 1stPlace и 2ndPlace.Так, например, в 2018 году «Реал Мадрид» победил «Ливерпуль», словарь будет выглядеть следующим образом:

2018: ["1stPlace": "Real Madrid",   "2ndPlace": "Liverpool"]

Предполагая, что эта переменная Data имеет результаты с 2018 по 2011 год. Если вы хотите узнать, кто победил в2018 вы можете сделать что-то вроде этого:

filteredData = Data.filter { $0.key == 2018 }

Если вы хотите знать, когда Реал Мадрид выиграл, вы так:

filteredData = Data.filter { $0.value["1stPlace"] == "Real Madrid" }

Если вы хотите знать, когда Реал Мадрид победил Атлетико МадридВы делаете это следующим образом:

filteredData = Data.filter {
  $0.value["2ndPlace"] == "Atlético Madrid" &&
  $0.value["1stPlace"] == "Real Madrid"
}

Когда у вас есть результаты в filteredData, вы можете выполнять запрос данных различными способами: вы можете сортировать по годам, вы можете извлечь только годы и т. д.

Следующий код представляет собой игровую площадку, которую я использовал для тестирования различных типов запросов:

import Foundation

typealias DictOfDicts = [Int : [String : String]]

var Data: DictOfDicts = [
  2018:
    ["1stPlace": "Real Madrid",   "2ndPlace": "Liverpool"],
  2017:
    ["1stPlace": "Real Madrid",   "2ndPlace": "Juventus"],
  2016:
    ["1stPlace": "Real Madrid",   "2ndPlace": "Atlético Madrid"],
  2015:
    ["1stPlace": "Barcelona",     "2ndPlace": "Juventus"],
  2014:
    ["1stPlace": "Real Madrid",   "2ndPlace": "Atlético Madrid"],
  2013:
    ["1stPlace": "Bayern Munich", "2ndPlace": "Borussia Dortmund"],
  2012:
    ["1stPlace": "Chelsea",       "2ndPlace": "Bayern Munich"],
  2011:
    ["1stPlace": "Barcelona",     "2ndPlace": "Manchester United"]
  ]

var filteredData: DictOfDicts = [:]

print("Results from 2017 to present")
print("----------------------------")
filteredData = Data.filter { $0.key >= 2017 } // Filter from 2017 to present
filteredData
  .sorted { $0.key > $1.key } // Sort by year
  .forEach {
    print("In \($0.key) \($0.value["1stPlace"]!) defeated \($0.value["2ndPlace"]!)")
  }
print("")

print("Results before 2015")
print("----------------------------")
filteredData = Data.filter { $0.key < 2015 } // Filter before 2015
filteredData
  .sorted { $0.key > $1.key } // Sort by year
  .forEach {
    print("In \($0.key) \($0.value["1stPlace"]!) defeated \($0.value["2ndPlace"]!)")
  }
print("")


filteredData = Data.filter { $0.value["1stPlace"] == "Real Madrid" } // Filter Real Madrid won
var years = filteredData
  .sorted { $0.key < $1.key } // Sort by year
  .map { "\($0.key)" } // Convert year to string
  .joined(separator: ", ") // Convert to comma separated single string
print("Real Madrid won in: \(years)")
print("")

filteredData = Data.filter { $0.value["2ndPlace"] == "Juventus" } // Filter Juventus lost
years = filteredData
  .sorted { $0.key > $1.key } // Sort by year
  .map { "\($0.key)" } // Convert year to string
  .joined(separator: ", ") // Convert to comma separated single string
print("Juventus lost the final match in: \(years)")
print("")

filteredData = Data.filter {
  $0.value["2ndPlace"] == "Atlético Madrid" &&
  $0.value["1stPlace"] == "Real Madrid"
} // Filter Real Madrid defeated Atlético Madrid
years = filteredData
  .sorted { $0.key > $1.key } // Sort by year
  .map { "\($0.key)" } // Convert year to string
  .joined(separator: ", ") // Convert to comma separated single string
print("Real Madrid defeated Atlético Madrid in: \(years)")
print()

let winnersAndChampionships =
  Set(Data.map { $0.value["1stPlace"]! }) // Get winners' names
  .map { winner in
    (winner, Data.filter { $0.value["1stPlace"] == winner }.count)
  } // Map for each winner the number of wins
  .sorted { $0.1 > $1.1}
print("Number of Champions League's wins per team")
print("------------------------------------------")
winnersAndChampionships.forEach {
  print("\($0.0): \($0.1)")
}

Вывод игровой площадки:

Results from 2017 to present
----------------------------
In 2018 Real Madrid defeated Liverpool
In 2017 Real Madrid defeated Juventus

Results before 2015
----------------------------
In 2014 Real Madrid defeated Atl&eacute;tico Madrid
In 2013 Bayern Munich defeated Borussia Dortmund
In 2012 Chelsea defeated Bayern Munich
In 2011 Barcelona defeated Manchester United

Real Madrid won in: 2014, 2016, 2017, 2018

Juventus lost the final match in: 2017, 2015

Real Madrid defeated Atl&eacute;tico Madrid in: 2016, 2014

Number of Champions League's wins per team
------------------------------------------
Real Madrid: 4
Barcelona: 2
Bayern Munich: 1
Chelsea: 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...