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

时间:2015-07-08 16:29:53

标签: ios arrays swift

说我有两个数组:

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个数组元素,然后返回一个双精度数组(如数据点,字符串数组的相似之处)。

3 个答案:

答案 0 :(得分:4)

我不清楚你在问什么,但是,你可能找到了对zipmapreduce有帮助的人。

例如,您可以像这样重写原始循环(假设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]

因为在前五场比赛中有一场比赛,而在最后一场比赛中也有一场比赛。