为了账号安全,请及时绑定邮箱和手机立即绑定

如何计算Swift数组中元素的出现次数?

/ 猿问

如何计算Swift数组中元素的出现次数?

慕粉4167745 2019-09-21 15:42:39

我已经看到了一些这样的示例,但是所有这些似乎都依赖于知道要计算发生次数的元素。我的数组是动态生成的,所以我无法知道要计算哪个元素的出现(我想计算所有元素的出现)。有人可以建议吗?

提前致谢

编辑:

也许我应该更清楚一点,数组将包含多个不同的字符串(例如 ["FOO", "FOO", "BAR", "FOOBAR"]

我如何在不知道它们是什么的情况下计算foo,bar和foobar的出现?


查看完整描述

3 回答

?
泛舟湖上清波郎朗

Swift 3和Swift 2:


您可以使用类型的字典[String: Int]来为您的每个项目建立计数[String]:


let arr = ["FOO", "FOO", "BAR", "FOOBAR"]

var counts: [String: Int] = [:]


for item in arr {

    counts[item] = (counts[item] ?? 0) + 1

}


print(counts)  // "[BAR: 1, FOOBAR: 1, FOO: 2]"


for (key, value) in counts {

    print("\(key) occurs \(value) time(s)")

}

输出:


BAR occurs 1 time(s)

FOOBAR occurs 1 time(s)

FOO occurs 2 time(s)

斯威夫特4:


Swift 4 引入了(SE-0165)可以在字典查找中包含默认值的功能,并且可以使用诸如+=和的操作对结果值进行突变-=,因此:


counts[item] = (counts[item] ?? 0) + 1

变为:


counts[item, default: 0] += 1

这使得使用forEach以下命令在一个简洁的行中进行计数操作变得容易:


let arr = ["FOO", "FOO", "BAR", "FOOBAR"]

var counts: [String: Int] = [:]


arr.forEach { counts[$0, default: 0] += 1 }


print(counts)  // "["FOOBAR": 1, "FOO": 2, "BAR": 1]"

斯威夫特4: reduce(into:_:)


Swift 4引入了一个新版本,reduce该版本使用inout变量来累加结果。使用它,计数的创建真正变成了一行:


let arr = ["FOO", "FOO", "BAR", "FOOBAR"]

let counts = arr.reduce(into: [:]) { counts, word in counts[word, default: 0] += 1 }


print(counts)  // ["BAR": 1, "FOOBAR": 1, "FOO": 2]

或使用默认参数:


let counts = arr.reduce(into: [:]) { $0[$1, default: 0] += 1 }

最后,您可以将其扩展为,Array以便可以在包含Hashable项的任何数组上调用它:


extension Array where Element: Hashable {

    var histogram: [Element: Int] {

        return self.reduce(into: [:]) { counts, elem in counts[elem, default: 0] += 1 }

    }

}

尽管我将其更改为计算属性,但还是从这个问题中借用了这个想法。


查看完整回答
反对 回复 2019-09-21
?
慕莱坞7535251

使用Swift 5时,您可以根据需要选择以下7个Playground示例代码之一来计算数组中可哈希项的出现次数。


#1。使用Array的reduce(into:_:)和Dictionary的subscript(_:default:)标

let array = [4, 23, 97, 97, 97, 23]

let dictionary = array.reduce(into: [:]) { counts, number in

    counts[number, default: 0] += 1

}

print(dictionary) // [4: 1, 23: 2, 97: 3]

#2。使用repeatElement(_:count:)函数,zip(_:_:)函数和Dictionary的init(_:uniquingKeysWith:)初始值设定项

let array = [4, 23, 97, 97, 97, 23]


let repeated = repeatElement(1, count: array.count)

//let repeated = Array(repeating: 1, count: array.count) // also works


let zipSequence = zip(array, repeated)


let dictionary = Dictionary(zipSequence, uniquingKeysWith: { (current, new) in

    return current + new

})

//let dictionary = Dictionary(zipSequence, uniquingKeysWith: +) // also works


print(dictionary) // prints [4: 1, 23: 2, 97: 3]

#3。使用Dictionary的init(grouping:by:)初始值设定项和mapValues(_:)方法

let array = [4, 23, 97, 97, 97, 23]


let dictionary = Dictionary(grouping: array, by: { $0 })


let newDictionary = dictionary.mapValues { (value: [Int]) in

    return value.count

}


print(newDictionary) // prints: [97: 3, 23: 2, 4: 1]

#4。使用Dictionary的init(grouping:by:)初始值设定项和map(_:)方法

let array = [4, 23, 97, 97, 97, 23]


let dictionary = Dictionary(grouping: array, by: { $0 })


let newArray = dictionary.map { (key: Int, value: [Int]) in

    return (key, value.count)

}


print(newArray) // prints: [(4, 1), (23, 2), (97, 3)]

#5。使用for循环和Dictionary的subscript(_:)下标

extension Array where Element: Hashable {


    func countForElements() -> [Element: Int] {

        var counts = [Element: Int]()

        for element in self {

            counts[element] = (counts[element] ?? 0) + 1

        }

        return counts

    }


}


let array = [4, 23, 97, 97, 97, 23]

print(array.countForElements()) // prints [4: 1, 23: 2, 97: 3]

#6。使用NSCountedSet和NSEnumerator的map(_:)方法(需要Foundation)

import Foundation


extension Array where Element: Hashable {


    func countForElements() -> [(Element, Int)] {

        let countedSet = NSCountedSet(array: self)

        let res = countedSet.objectEnumerator().map { (object: Any) -> (Element, Int) in

            return (object as! Element, countedSet.count(for: object))

        }

        return res

    }


}


let array = [4, 23, 97, 97, 97, 23]

print(array.countForElements()) // prints [(97, 3), (4, 1), (23, 2)]

#7。使用NSCountedSet和AnyIterator(需要Foundation)

import Foundation


extension Array where Element: Hashable {


    func counForElements() -> Array<(Element, Int)> {

        let countedSet = NSCountedSet(array: self)

        var countedSetIterator = countedSet.objectEnumerator().makeIterator()

        let anyIterator = AnyIterator<(Element, Int)> {

            guard let element = countedSetIterator.next() as? Element else { return nil }

            return (element, countedSet.count(for: element))

        }

        return Array<(Element, Int)>(anyIterator)

    }


}


let array = [4, 23, 97, 97, 97, 23]

print(array.counForElements()) // [(97, 3), (4, 1), (23, 2)]


查看完整回答
反对 回复 2019-09-21
?
蓝山帝景

我更新了oisdk对Swift2的回答。


14/04/14我将此代码更新为Swift2.2


16/10/11更新为Swift3


哈希的:


extension Sequence where Self.Iterator.Element: Hashable {

    private typealias Element = Self.Iterator.Element


    func freq() -> [Element: Int] {

        return reduce([:]) { (accu: [Element: Int], element) in

            var accu = accu

            accu[element] = accu[element]?.advanced(by: 1) ?? 1

            return accu

        }

    }

}

Equatable:


extension Sequence where Self.Iterator.Element: Equatable {

    private typealias Element = Self.Iterator.Element


    func freqTuple() -> [(element: Element, count: Int)] {


        let empty: [(Element, Int)] = []


        return reduce(empty) { (accu: [(Element, Int)], element) in

            var accu = accu

            for (index, value) in accu.enumerated() {

                if value.0 == element {

                    accu[index].1 += 1

                    return accu

                }

            }


            return accu + [(element, 1)]

        }

    }

}

用法


let arr = ["a", "a", "a", "a", "b", "b", "c"]

print(arr.freq()) // ["b": 2, "a": 4, "c": 1]

print(arr.freqTuple()) // [("a", 4), ("b", 2), ("c", 1)]

for (k, v) in arr.freq() {

    print("\(k) -> \(v) time(s)")

}

// b -> 2 time(s)

// a -> 4 time(s)

// c -> 1 time(s)


for (element, count) in arr.freqTuple() {

    print("\(element) -> \(count) time(s)")

}

// a -> 4 time(s)

// b -> 2 time(s)

// c -> 1 time(s)


查看完整回答
反对 回复 2019-09-21

添加回答

回复

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信