当前位置: 首页 > 面试题库 >

如何在Swift中按数组元素分组

柴凌
2023-03-14
问题内容

假设我有以下代码:

class Stat {
   var statEvents : [StatEvents] = []
}

struct StatEvents {
   var name: String
   var date: String
   var hours: Int
}


var currentStat = Stat()

currentStat.statEvents = [
   StatEvents(name: "lunch", date: "01-01-2015", hours: 1),
   StatEvents(name: "dinner", date: "01-01-2015", hours: 1),
   StatEvents(name: "dinner", date: "01-01-2015", hours: 1),
   StatEvents(name: "lunch", date: "01-01-2015", hours: 1),
   StatEvents(name: "dinner", date: "01-01-2015", hours: 1)
]

var filteredArray1 : [StatEvents] = []
var filteredArray2 : [StatEvents] = []

我可以手动调用下一个函数多次,以使2个数组按“相同名称”分组。

filteredArray1 = currentStat.statEvents.filter({$0.name == "dinner"})
filteredArray2 = currentStat.statEvents.filter({$0.name == "lunch"})

问题是我不知道变量值,在这种情况下为“ dinner”和“
lunch”,因此我想按名称自动对这个statEvents数组进行分组,所以当名称不同时,我会得到尽可能多的数组。

我该怎么办?


问题答案:

从Swift
4开始,此功能已添加到标准库中。您可以这样使用它:

Dictionary(grouping: statEvents, by: { $0.name })
[
  "dinner": [
    StatEvents(name: "dinner", date: "01-01-2015", hours: 1),
    StatEvents(name: "dinner", date: "01-01-2015", hours: 1),
    StatEvents(name: "dinner", date: "01-01-2015", hours: 1)
  ],
  "lunch": [
    StatEvents(name: "lunch", date: "01-01-2015", hours: 1),
    StatEvents(name: "lunch", date: "01-01-2015", hours: 1)
]

斯威夫特3:

public extension Sequence {
    func group<U: Hashable>(by key: (Iterator.Element) -> U) -> [U:[Iterator.Element]] {
        var categories: [U: [Iterator.Element]] = [:]
        for element in self {
            let key = key(element)
            if case nil = categories[key]?.append(element) {
                categories[key] = [element]
            }
        }
        return categories
    }
}

不幸的是,append上面的函数复制了基础数组,而不是对其进行适当的突变,这是更好的选择。这会导致很大的减速。您可以通过使用引用类型包装器解决该问题:

class Box<A> {
  var value: A
  init(_ val: A) {
    self.value = val
  }
}

public extension Sequence {
  func group<U: Hashable>(by key: (Iterator.Element) -> U) -> [U:[Iterator.Element]] {
    var categories: [U: Box<[Iterator.Element]>] = [:]
    for element in self {
      let key = key(element)
      if case nil = categories[key]?.value.append(element) {
        categories[key] = Box([element])
      }
    }
    var result: [U: [Iterator.Element]] = Dictionary(minimumCapacity: categories.count)
    for (key,val) in categories {
      result[key] = val.value
    }
    return result
  }
}

即使您两次遍历最终字典,此版本在大多数情况下仍比原始字典快。

斯威夫特2:

public extension SequenceType {

  /// Categorises elements of self into a dictionary, with the keys given by keyFunc

  func categorise<U : Hashable>(@noescape keyFunc: Generator.Element -> U) -> [U:[Generator.Element]] {
    var dict: [U:[Generator.Element]] = [:]
    for el in self {
      let key = keyFunc(el)
      if case nil = dict[key]?.append(el) { dict[key] = [el] }
    }
    return dict
  }
}

在您的情况下,您可以keyFunc使用以下名称返回“ keys” :

currentStat.statEvents.categorise { $0.name }
[  
  dinner: [
    StatEvents(name: "dinner", date: "01-01-2015", hours: 1),
    StatEvents(name: "dinner", date: "01-01-2015", hours: 1),
    StatEvents(name: "dinner", date: "01-01-2015", hours: 1)
  ], lunch: [
    StatEvents(name: "lunch", date: "01-01-2015", hours: 1),
    StatEvents(name: "lunch", date: "01-01-2015", hours: 1)
  ]
]

因此,您将获得一个字典,其中每个键都是一个名称,每个值都是具有该名称的StatEvents的数组。

斯威夫特1

func categorise<S : SequenceType, U : Hashable>(seq: S, @noescape keyFunc: S.Generator.Element -> U) -> [U:[S.Generator.Element]] {
  var dict: [U:[S.Generator.Element]] = [:]
  for el in seq {
    let key = keyFunc(el)
    dict[key] = (dict[key] ?? []) + [el]
  }
  return dict
}

categorise(currentStat.statEvents) { $0.name }

给出输出:

extension StatEvents : Printable {
  var description: String {
    return "\(self.name): \(self.date)"
  }
}
print(categorise(currentStat.statEvents) { $0.name })
[
  dinner: [
    dinner: 01-01-2015,
    dinner: 01-01-2015,
    dinner: 01-01-2015
  ], lunch: [
    lunch: 01-01-2015,
    lunch: 01-01-2015
  ]
]

(swiftstub在这里)



 类似资料:
  • 问题内容: 如何使用Apple的新语言Swift取消设置/删除数组中的元素? 这是一些代码: 如何从数组中删除元素? 问题答案: 该关键字是声明不能改变的常量。如果要修改变量,则应改用,例如: 一个使原始集合保持不变的非变异替代方法是用于创建一个新集合,而无需删除想要删除的元素,例如:

  • 问题内容: 假设我有一个数组,例如: 然后我想将一个元素推/追加到所述数组的末尾,以获得: 我应该使用哪种方法? 那我想在数组的 前面 添加一个元素呢?是否有固定的时间班次? 问题答案: 从 Swift 3/4/5开始 ,操作如下。 向数组末尾添加新元素。 将另一个数组附加到数组的末尾。 向您的数组中插入一个新元素。 将另一个数组的内容插入到数组中。 更多信息可以从第110页开始的“ Swift编

  • 我想从数组创建所有可能的数组可能大于或小于。输出数组中的元素不必是唯一的。 例如: 根据这个数组 给定所需大小的函数,应返回: 例2 根据这个数组 给定所需大小的函数,应返回: 用Swift怎么做?

  • 我必须在Elasticsearch中构造一个非常重要的查询(现在看来是这样)。假设我有两个实体,每个实体都有一个数组元素,由字符串组成: 数组元素的映射如下(使用动态模板): 实体的Json表示如下: 然后我有了用户输入:['A','B','C']。 我想要实现的是找到只包含输入中指定元素的实体——预期结果是:[A'、[B']、[A'、[C']、[A'],但不是['A'、[E'](因为用户输入中不

  • 问题内容: 我已经看到了一些这样的示例,但是所有这些似乎都依赖于知道要计算发生次数的元素。我的数组是动态生成的,所以我无法知道要计算哪个元素的出现(我想计算所有元素的出现)。有人可以建议吗? 提前致谢 编辑: 也许我应该更清楚一点,数组将包含多个不同的字符串(例如 在不知道它们是什么的情况下,如何计算foo,bar和foobar的出现? 问题答案: Swift 3和Swift 2: 您可以使用类型

  • 问题内容: 快速找到整数数组总和的最简单(最佳)方法是什么?我有一个称为倍数的数组,我想知道倍数的总和。 问题答案: 这是我能找到的最简单/最短的方法。 Swift 3和Swift 4: 斯威夫特2: 更多信息: 这使用了Array的reduce方法(在此处提供文档),该方法允许您“通过递归应用所提供的闭包将元素的集合减少到单个值”。我们给它0作为初始值,然后本质上给闭包赋值。当然,我们可以将其简