在Swift 5中使用嵌套字典过滤字典

时间:2019-09-28 22:40:04

标签: swift dictionary filter

我有一个包含嵌套字典作为值的字典。我要完成的工作是搜索嵌套字典,然后将那些匹配的值添加到名为“ 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 个答案:

答案 0 :(得分:1)

为了给您一些示例,我如何在冠军联赛中从获胜者和亚军中获得一组数据进行过滤。在主词典中,package calculator1; import javax.swing.*; import java.awt.*; import java.awt.event.*; class MyFirstGUI extends JFrame implements ActionListener { int val1 = 0; int val2 = 0; int sum = 0; JTextField t1 = new JTextField(10); JButton b1 = new JButton("+"); JButton b2 = new JButton("*"); JButton b3 = new JButton("/"); JButton b4 = new JButton("="); int n1, n2; public MyFirstGUI() { setLayout(new FlowLayout()); setVisible(true); setSize(500, 500); JLabel l1 = new JLabel("Result"); add(l1); add(t1); add(b1); add(b2); add(b3); add(b4); b1.addActionListener(this); b2.addActionListener(this); b3.addActionListener(this); b4.addActionListener(this); } public void actionPerformed(ActionEvent e) { int val1, val2, sum = 0; val1 = Integer.parseInt(t1.getText()); if (e.getSource() == b1) { t1.setText(""); } if (e.getSource() == b4) { val2 = Integer.parseInt(t1.getText()); sum = val1 + val2; t1.setText("" + sum); } } } class Test { public static void main(String[] args) { MyFirstGUI p = new MyFirstGUI(); } } 键对应于比赛的年份。里面的字典有两个键:Int1stPlace。例如,在2018年皇家马德里击败利物浦的比赛中,字典将如下所示:

2ndPlace

假设这种结构,2018: ["1stPlace": "Real Madrid", "2ndPlace": "Liverpool"] 变量的结果为2018年至2011年。如果您想知道谁在2018年获胜,可以执行以下操作:

Data

如果您想知道皇马何时获胜,您会像这样:

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)")
}

答案 1 :(得分:1)

首先,您不需要NSPredicate来完成如此简单的任务,String.contains()应该也可以工作。

第二,您可以结合使用mapValuescompactMapValues来实现目标:

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:< / p>

let filteredData = data.compactMapValues {
    let filteredDict = $0.compactMapValues { $0.contains(searchQuery) ? $0 : nil }
    return filteredDict.isEmpty ? nil: filteredDict
}