两个字符串阵列的双打数组

时间:2022-06-16 12:42:54

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.

因为在前五个中有一个匹配,在最后一个也有一个匹配。