【问题标题】:Get Subset of array based on the occurrence of elements根据元素的出现获取数组的子集
【发布时间】:2018-06-25 18:49:17
【问题描述】:

我有一个类似的数组:

var arr = [4,1,5,5,3]

我想根据其中元素的出现从数组中获取子集。

例如:

Elements with frequency 1 is {4,1,3}
Elements with frequency 2 is {5,5}

我关注了这个StackOverflow question,但无法弄清楚如何做上述事情。

有什么办法可以做到吗?

【问题讨论】:

  • 能否请您对my answer进行评论和/或奖励?

标签: ios arrays swift3


【解决方案1】:

您可以使用NSCountedSet 来获取arr 中所有元素的计数,然后您可以构建Dictionary,其中键是元素的出现次数,值是数组具有关键出现次数的元素。通过迭代 Set(arr) 而不是简单地 arr 来构建字典,您可以确保重复元素只添加一次到字典中(例如,对于您的原始示例,5 不会添加两次,因为频率为 2)。

对于打印,您只需要遍历 Dictionary 的键并打印键及其对应的值。我只是对键进行排序,以使打印按出现次数的升序进行。

let arr = [4,1,5,5,3,2,3,6,2,7,8,2,7,2,8,8,8,7]
let counts = NSCountedSet(array: arr)
var countDict = [Int:[Int]]()
for element in Set(arr) {
    countDict[counts.count(for: element), default: []].append(element)
}
countDict

for freq in countDict.keys.sorted() {
    print("Elements with frequency \(freq) are {\(countDict[freq]!)}")
}

输出:

Elements with frequency 1 are {[4, 6, 1]}
Elements with frequency 2 are {[5, 3]}
Elements with frequency 3 are {[7]}
Elements with frequency 4 are {[2, 8]}

Swift 3 版本:

let arr = [4,1,5,5,3,2,3,6,2,7,8,2,7,2,8,8,8,7]
let counts = NSCountedSet(array: arr)
var countDict = [Int:[Int]]()
for element in Set(arr) {
    if countDict[counts.count(for: element)] != nil {
        countDict[counts.count(for: element)]!.append(element)  
    } else {
        countDict[counts.count(for: element)] = [element]
    }
}

for freq in countDict.keys.sorted() {
    print("Elements with frequency \(freq) are {\(countDict[freq]!)}")
}

【讨论】:

  • 请注意,使用 NSCountedSet 不会保持数组顺序
  • @Dávid Pásztor 我收到错误消息“无法使用类型为 '(Int,默认值:[Any])'(又名' (Int, 默认: Array)')"
  • @Rumin 您确定您使用的代码与我的完全相同吗?哪一行会抛出该错误?对我来说,代码在操场上运行得很好。顺便说一句,您还必须确保已导入 Foundation(如果您导入 UIKit,那也将导入 Foundation)以使用 NSCountedSet
  • 是的,我在操场上运行相同的代码。我还导入了 Foundation。请检查您是否提供了与您正在运行的代码相同的代码。
  • @Rumin 是的,这与我在 Playground 中运行的代码完全相同。它还在 IBM Swift 沙箱have a look yourself 上完美运行。你用的是什么 Swift 版本?我的代码使用 Swift 4。
【解决方案2】:

您只需要获取元素的出现并过滤仅出现一次或多次的元素,如answer所示:

extension Array where Element: Hashable {
    // Swift 4 or later
    var occurrences: [Element: Int] {
        return reduce(into: [:]) { $0[$1, default: 0] += 1 }
    }
    // // for Swift 3 or earlier
    // var occurrences: [Element: Int] {
    //     var result: [Element: Int] = [:]
    //     forEach{ result[$0] = (result[$0] ?? 0) + 1}
    //     return result
    // }
    func frequencies(where isIncluded: (Int) -> Bool) -> Array {
        return filter{ isIncluded(occurrences[$0] ?? 0) }
    }
}

游乐场测试:

let arr = [5, 4, 1, 5, 5, 3, 5, 3]

let frequency1 = arr.frequencies {$0 == 1}       // [4, 1]
let frequency2 = arr.frequencies {$0 == 2}       // [3, 3]
let frequency3orMore = arr.frequencies {$0 >= 3} // [5, 5, 5, 5]

【讨论】:

  • 我收到错误消息:“无法使用 '(_, default: Int)' 类型的索引来下标 '[_ : Int]' 类型的值”
  • @Rumin 你的 Xcode 版本是多少?你在使用 Swift 4 吗?
  • 频率为 N 的元素呢?
【解决方案3】:

就是这样:

func getSubset(of array: [Int], withFrequency frequency: Int) -> [Int]
{
    var counts: [Int: Int] = [:]

    for item in array
    {
        counts[item] = (counts[item] ?? 0) + 1
    }

    let filtered  = counts.filter{ $0.value == frequency}

    return Array(filtered.keys)
}

这是纯 Swift(不使用旧的 Next Step 类),并且正在使用您提供的 SO 链接中的想法。

counts 字典包含数组中每个 int 值(键)的频率(值):[int-value : frequency]

【讨论】:

  • 重要的是要注意这个函数实际上并不能解决整个问题。您需要知道阵列中存在哪些频率才能有效地使用此功能。在不知道这一点的情况下,如果想要找到数组的所有子集,您的函数的性能就会变得非常糟糕。
  • @DávidPásztor 我认为这就是我们所要求的。目前的频率在counts 中可用,所以如果也需要,将这个逻辑塑造成另一种形状非常简单。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多