Say I have two arrays:
说我有两个数组:
let arrayOne = ["Hi", "Hi", "Hello", "Not Hey", "Howdy", "Hi"]
let arrayTwo = ["Hi", "Hello", "Hey", "Not Howdy", "Hi", "Hi"]
and I have this for loop that gets the percent similarity of the doubles:
我有这个for循环,它获得双打的百分比相似性:
var matches = 0
for (index, item) in enumerate(arrayOne) {
if item == arrayTwo[index] {
matches++
}
}
However, what if those arrays are longer and I want data points of those similarities instead of one single calculation. What kind of a function could I write where it takes the first 5 elements off the array, returns their similarity with the for loop, and moves on to the next 5? ie. it would be a function that takes two string arrays and returns an array of doubles. I am sure this is a simple question but I do not know how to approach taking 5 array elements at a time and then returning an array of doubles (like data points the the string array similarities).
但是,如果那些数组更长并且我想要那些相似性的数据点而不是一次计算,那该怎么办呢?我可以编写什么样的函数来从数组中取出前5个元素,返回它们与for循环的相似性,然后继续下一个5?即。它将是一个函数,它接受两个字符串数组并返回一个双精度数组。我确信这是一个简单的问题,但我不知道如何一次获取5个数组元素,然后返回一个双精度数组(如数据点,字符串数组的相似之处)。
3 个解决方案
#1
1
Take a look at this. I think it does what you are asking. By introducing a count
variable to keep track of the number of items you have processed, you will know when to update your counts
array:
看看这个。我认为它符合您的要求。通过引入计数变量来跟踪已处理的项目数,您将知道何时更新计数数组:
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
4
I’m not clear quite what you’re asking, however, you might find playing around with zip
, map
, and reduce
helpful.
我不太清楚你在问什么,但是,你可能会发现玩拉链,地图和减少有用。
For example, you could rewrite your original loop like this (assuming Swift 2.0, you’d have to rearrange slightly for 1.2):
例如,您可以像这样重写原始循环(假设Swift 2.0,您必须稍微重新排列1.2):
zip(arrayOne, arrayTwo).reduce(0) { $0 + ($1.0 == $1.1 ? 1 : 0) }
// returns 4
zip
creates a new sequence of the pairs of elements at each corresponding position.
zip在每个相应位置创建元素对的新序列。
reduce
takes a starting value, then keeps a running value by applying a function to the current value and the next value in the sequence – bearing in mind this is a sequence of pair elements, you want to add 1 when they are the same, 0 when they aren’t. This then gives you a count of the positions where both match.
reduce取一个起始值,然后通过将函数应用于当前值和序列中的下一个值来保持运行值 - 记住这是一对对元素,你想在它们相同时加1,0当他们不是。然后,它会计算两者匹配的位置。
If instead you wanted an array, with true representing a match at that point, and false if different, you could use map
:
如果您想要一个数组,其中true代表该点的匹配,如果不同则为false,您可以使用map:
zip(arrayOne, arrayTwo).map(==)
// returns [true, false, false, false, false, true]
If on the other hand you wanted a list of the differences in string length between the two strings at each position, you could change it to:
另一方面,如果您想要每个位置的两个字符串之间的字符串长度差异列表,您可以将其更改为:
zip(arrayOne, arrayTwo).map { (a,b) in
a.characters.count - b.characters.count
}
// returns [0, -3, 2, -2, 3, 0]
As some have suggested, Set
might help, e.g.:
正如一些人所说,Set可能有所帮助,例如:
let commonElements = Set(arrayOne).intersect(arrayTwo)
// returns strings present in both e.g. {"Hi", "Hello”}
This is a good approach if you are OK treating your data as a set i.e. order doesn’t matter and duplicates can be ignored. If order and dupes do matter, you probably have to stick with arrays.
如果您可以将数据视为一组,即顺序无关紧要,可以忽略重复项,这是一种很好的方法。如果订单和欺骗行为很重要,您可能必须坚持使用数组。
#3
1
Right - so I think I understand what you're looking for: you want to have a matches
function like the one you've written that works for chunks of a certain number of elements. First off, you're going to need a chunk function. There's a good discussion of them here, but they're for arrays, and you're going to want to zip your two arrays together here, so you'll need one for SequenceType
. This works:
是的 - 所以我想我明白你在寻找什么:你想要一个匹配函数,就像你编写的那个函数适用于一定数量元素的块。首先,你需要一个块功能。这里对它们进行了很好的讨论,但是它们是用于数组的,而且你想在这里将两个数组压缩在一起,所以你需要一个用于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
}
}
Then, you need a function that counts the matches in two arrays. You could inline it with a closure, or you could define it separately, it doesn't make much of a difference.
然后,您需要一个对两个数组中的匹配进行计数的函数。你可以用一个闭包来内联它,或者你可以单独定义它,它没有太大的区别。
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 } }
}
That will return:
那会回来:
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]
Since in the first five there's one match, and in the last there is one as well.
因为在前五个中有一个匹配,在最后一个也有一个匹配。
#1
1
Take a look at this. I think it does what you are asking. By introducing a count
variable to keep track of the number of items you have processed, you will know when to update your counts
array:
看看这个。我认为它符合您的要求。通过引入计数变量来跟踪已处理的项目数,您将知道何时更新计数数组:
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
4
I’m not clear quite what you’re asking, however, you might find playing around with zip
, map
, and reduce
helpful.
我不太清楚你在问什么,但是,你可能会发现玩拉链,地图和减少有用。
For example, you could rewrite your original loop like this (assuming Swift 2.0, you’d have to rearrange slightly for 1.2):
例如,您可以像这样重写原始循环(假设Swift 2.0,您必须稍微重新排列1.2):
zip(arrayOne, arrayTwo).reduce(0) { $0 + ($1.0 == $1.1 ? 1 : 0) }
// returns 4
zip
creates a new sequence of the pairs of elements at each corresponding position.
zip在每个相应位置创建元素对的新序列。
reduce
takes a starting value, then keeps a running value by applying a function to the current value and the next value in the sequence – bearing in mind this is a sequence of pair elements, you want to add 1 when they are the same, 0 when they aren’t. This then gives you a count of the positions where both match.
reduce取一个起始值,然后通过将函数应用于当前值和序列中的下一个值来保持运行值 - 记住这是一对对元素,你想在它们相同时加1,0当他们不是。然后,它会计算两者匹配的位置。
If instead you wanted an array, with true representing a match at that point, and false if different, you could use map
:
如果您想要一个数组,其中true代表该点的匹配,如果不同则为false,您可以使用map:
zip(arrayOne, arrayTwo).map(==)
// returns [true, false, false, false, false, true]
If on the other hand you wanted a list of the differences in string length between the two strings at each position, you could change it to:
另一方面,如果您想要每个位置的两个字符串之间的字符串长度差异列表,您可以将其更改为:
zip(arrayOne, arrayTwo).map { (a,b) in
a.characters.count - b.characters.count
}
// returns [0, -3, 2, -2, 3, 0]
As some have suggested, Set
might help, e.g.:
正如一些人所说,Set可能有所帮助,例如:
let commonElements = Set(arrayOne).intersect(arrayTwo)
// returns strings present in both e.g. {"Hi", "Hello”}
This is a good approach if you are OK treating your data as a set i.e. order doesn’t matter and duplicates can be ignored. If order and dupes do matter, you probably have to stick with arrays.
如果您可以将数据视为一组,即顺序无关紧要,可以忽略重复项,这是一种很好的方法。如果订单和欺骗行为很重要,您可能必须坚持使用数组。
#3
1
Right - so I think I understand what you're looking for: you want to have a matches
function like the one you've written that works for chunks of a certain number of elements. First off, you're going to need a chunk function. There's a good discussion of them here, but they're for arrays, and you're going to want to zip your two arrays together here, so you'll need one for SequenceType
. This works:
是的 - 所以我想我明白你在寻找什么:你想要一个匹配函数,就像你编写的那个函数适用于一定数量元素的块。首先,你需要一个块功能。这里对它们进行了很好的讨论,但是它们是用于数组的,而且你想在这里将两个数组压缩在一起,所以你需要一个用于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
}
}
Then, you need a function that counts the matches in two arrays. You could inline it with a closure, or you could define it separately, it doesn't make much of a difference.
然后,您需要一个对两个数组中的匹配进行计数的函数。你可以用一个闭包来内联它,或者你可以单独定义它,它没有太大的区别。
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 } }
}
That will return:
那会回来:
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]
Since in the first five there's one match, and in the last there is one as well.
因为在前五个中有一个匹配,在最后一个也有一个匹配。