我在StackOverflow上遇到了一个问题:Swift - Convert Array to Dictionary用户想要获取数组中的元素并将其放入字典中,并为每个元素分配0。 (关键是玩家,价值是他们的分数)因此:
var playerNames = ["Harry", "Ron", "Hermione"]
成为
var scoreBoard: [String:Int] = [ "Ron":0, "Harry":0, "Hermione":0 ]
此问题有2个答案:1)在数组上使用reduce
let scoreboard = playerNames.reduce(into: [String: Int]()) { $0[$1] = 0 }
2)创建一个字典并遍历数组以向其中添加每个值键对
var dictionary = [String: Int]()
for player in playerNames {
dictionary[player] = 0
}
我从https://github.com/nyisztor/swift-algorithms中使用BenchTimer函数来测试这两种求解方式。而且它们似乎都在O(n)中运行。
我想知道为什么我们比第一个更喜欢第一个,因为写第二个解决方案的人对他们的编码技能有不好的评价。
编辑:Apple在较新的版本中不赞成使用某些功能,所以坚持基本知识并创建我们自己的处理方式不是更好吗?
谢谢您的回答
[今天,IMO,您不应使用其中任何一种。现在,我们有了Dictionary.init(uniqueKeysWithValues:)
和.init(_:uniquingKeysWith:)
,它们可以更清楚地说明它们的意图,并明确显示极端情况,例如重复的键。
如果您可以静态证明所有键都是唯一的,那么您将使用第一个键:
let scoreboard = Dictionary(uniqueKeysWithValues: playerNames.map { (name: $0, score: 0) })
如果无法证明密钥是唯一的,则可以使用第二个密钥,这将使您可以明确决定在发生冲突时该怎么做。
let scoreboard = Dictionary(playerNames.map { (name: $0, score: 0) },
uniquingKeysWith: { first, _ in first })
请注意,这种方法如何使标签清楚显示键是什么,值是什么。我尚未对该代码进行基准测试,但是我希望它在时间上与其他代码非常相似。
一般来说,由于一些原因,您应该比for循环更喜欢使用函数式习惯用法(即reduce):
该功能版本在默认情况下是正确的,因为已经过测试。在reduce的情况下,这看似微不足道,但在shuffled
之类的情况下,它就显得微不足道了。您如何轻松地查看for循环并告诉我它是否执行了Fisher Yates改组以及该改组是否正确实施?类似地,函数流水线比一堆顺序的for循环或执行5种不同功能的单个for循环更容易阅读。
功能版本通常(但不是在这种情况下)是不可变的,并且不可变的值比可变状态更易于推论,因为它们永远不会改变。
Swift.Sequence
上的功能方法大多与Combine.Publisher
上的方法相似。这意味着您可以在所有序列中使用一组功能惯用语,无论它们是同步的还是异步的/反应式的。
所以坚持基础知识并创建我们自己的做事方式更好吗?
我不这么认为。 Swift社区当然不是那种心态。 Swift会优先进行有意义的抽象和简化,只要它们是有价值的且逐步公开即可。
围棋社区分享了您的想法,但这非常痛苦(IMO)。 Go标准库甚至没有用于反转字符串的API。你必须自己煮。而且这比大多数人想的要难。如果您认为做一个循环来反转字节的简单问题,不对,对于unicode来说这是完全不可行的(但在"hello"
之类的简单ASCII测试用例中可能不会引起注意)。
类似地,如果每次要实现for
时都编写map
循环,则可能会忘记调用Array.reserveCapacity(_:)
。忘记这将导致多个数组分配,并使您的O(n)
外观算法实际上成为O(n^2)
。这样的性能或正确性“陷阱”很少,因此使用流行的,共享的实现有很大的好处。
我们站在巨人的肩膀上。如果我们全神贯注于重新发明轮子,我们将无法做到这一点。
我不会使用它们中的任何一个
第一种方法:
第二种方法:
reduce
),但不适合该作业(Dictionary.init(uniqueKeysWithValues:)
)。参见https://github.com/amomchilov/Blog/blob/master/Don't%20abuse%20reduce.md相反,我建议使用Rob Napier或Martin R's approach。两者都更能表达您的意图,并使用Dictionary.init(uniqueKeysWithValues:)
,可在内部为字典预先分配足够的内存,以适应所有值。]