说我有两个数组:
let arrayOne = ["Hi", "Hi", "Hello", "Not Hey", "Howdy", "Hi"]
let arrayTwo = ["Hi", "Hello", "Hey", "Not Howdy", "Hi", "Hi"]
我有这个for循环,它获得了双打的百分比相似度:
var matches = 0
for (index, item) in enumerate(arrayOne) {
if item == arrayTwo[index] {
matches++
}
}
然而,如果那些数组更长并且我想要那些相似性的数据点而不是一次计算,那该怎么办呢?我可以写出什么样的函数,它从数组中取出前5个元素,返回它们与for循环的相似性,然后继续下一个5?即。它将是一个函数,它接受两个字符串数组并返回一个双精度数组。我确信这是一个简单的问题,但我不知道如何一次获取5个数组元素,然后返回一个双精度数组(如数据点,字符串数组的相似之处)。
答案 0 :(得分:4)
我不清楚你在问什么,但是,你可能找到了对zip
,map
和reduce
有帮助的人。
例如,您可以像这样重写原始循环(假设Swift 2.0,您必须稍微重新排列1.2):
zip(arrayOne, arrayTwo).reduce(0) { $0 + ($1.0 == $1.1 ? 1 : 0) }
// returns 4
zip
在每个相应位置创建一对元素对的新序列。
reduce
获取一个起始值,然后通过将函数应用于当前值和序列中的下一个值来保持运行值 - 请记住这是一对配对元素,您要添加1当他们是相同的时,0他们不相同时。然后,这会计算两者匹配的位置。
如果您想要一个数组,其中true代表该点的匹配,如果不同则为false,您可以使用map
:
zip(arrayOne, arrayTwo).map(==)
// returns [true, false, false, false, false, true]
另一方面,如果您想要每个位置的两个字符串之间的字符串长度差异列表,您可以将其更改为:
zip(arrayOne, arrayTwo).map { (a,b) in
a.characters.count - b.characters.count
}
// returns [0, -3, 2, -2, 3, 0]
正如一些人所建议的,Set
可能有所帮助,例如:
let commonElements = Set(arrayOne).intersect(arrayTwo)
// returns strings present in both e.g. {"Hi", "Hello”}
如果您可以将数据视为一组,那么这是一种很好的方法,即顺序无关紧要,可以忽略重复项。如果订单和欺骗行为很重要,您可能必须坚持使用数组。
答案 1 :(得分:1)
看看这个。我认为它符合您的要求。通过引入count
变量来跟踪您处理的项目数量,您将知道何时更新counts
数组:
var matches = 0
let arrayOne = ["Hi", "Hi", "Hello", "Not Hey", "Howdy", "Hi", "a", "b", "c"]
let arrayTwo = ["Hi", "Hello", "Hey", "Not Howdy", "Hi", "Hi", "a", "B", "C"]
var count = 0
var counts:[Int] = []
for (index, item) in enumerate(arrayOne) {
if item == arrayTwo[index] {
matches++
}
// Have we done 5? If so, time to update counts array
if ++count == 5 {
counts.append(matches)
count = 0
matches = 0
}
}
// If we didn't have 5, just append the matches for the remaining items
if count > 0 {
counts.append(matches)
}
println(counts) // prints "[1, 2]"
答案 2 :(得分:1)
是的 - 所以我认为我理解你正在寻找的东西:你想拥有一个matches
函数,就像你编写的那个函数适用于一定数量元素的块。首先,您需要一个块功能。我们对它们进行了很好的讨论here,但它们适用于数组,并且您希望将这两个数组压缩在一起,因此您需要一个SequenceType
。这有效:
public extension SequenceType {
/// Returns an array of arrays of n non-overlapping elements of self
/// - Parameter n: The size of the chunk
/// ```swift
/// [1, 2, 3, 4, 5].chunk(2)
///
/// [[1, 2], [3, 4], [5]]
/// ```
func chunk(_ n: Int) -> [[Generator.Element]] {
var g = self.generate()
var ret: [[Generator.Element]] = [[]]
while let next = g.next() {
if ret.last!.count < n {
ret[ret.endIndex.predecessor()].append(next)
} else {
ret.append([next])
}
}
return ret
}
}
然后,您需要一个对两个数组中的匹配进行计数的函数。你可以用一个闭包来内联它,或者你可以单独定义它,它没有太大的区别。
func matchesEvery<
S0 : SequenceType,
S1 : SequenceType,
T : Equatable where
S0.Generator.Element == T,
S1.Generator.Element == T
>(_ n: Int, s0: S0, s1: S1) -> [Int] {
return zip(s0, s1)
.chunk(5)
.map { $0.reduce(0) { $1.0 == $1.1 ? $0 + 1 : $0 } }
}
那将返回:
let arrayOne = ["Hi", "Hi", "Hello", "Not Hey", "Howdy", "Hi"]
let arrayTwo = ["Hi", "Hello", "Hey", "Not Howdy", "Hi", "Hi"]
matchesEvery(5, s0: arrayOne, s1: arrayTwo) // [1, 1]
因为在前五场比赛中有一场比赛,而在最后一场比赛中也有一场比赛。