给定Dictionary<String, Arrary<Int>>
找到5
中第一个Array<Int>
条目中有多少个条目具有相同的两个指定值。
例如:
假设:
let numberSeries = [
"20022016": [07,14,36,47,50,02,05],
"13022016": [16,07,32,36,41,07,09],
"27022016": [14,18,19,31,36,04,05],
]
值为7
和36
,结果应为2
,因为第一个和第二个条目都包含值7
和36
条目数组的前5个条目。
我试图通过很多方式实现这一目标,但我无法让它发挥作用。
这是我目前的尝试:
//created a dictionary with (key, values)
let numberSeries = [
"20022016": [07,14,36,47,50,02,05],
"13022016": [16,07,32,36,41,07,09],
"27022016": [14,18,19,31,36,04,05],
]
var a = 07 //number to look for
var b = 36 // number to look for
// SearchForPairAB // search for pair // Doesn't Work.
var ab = [a,b] // pair to look for
var abPairApearedCount = 0
for (kind, numbers) in numberSeries {
for number in numbers[0...4] {
if number == ab { //err: Cannot invoke '==' with argument listof type Int, @Value [Int]
abPairApearedCount++
}
}
}
这会在行Cannot invoke '==' with argument listof type Int, @Value [Int]
if number == ab
答案 0 :(得分:2)
您无法使用==
来比较Int
和Array<Int>
,从比较的角度来看,这没有任何意义。有很多不同的方法可以实现你想要做的事情。在这种情况下,我可能会使用map
/ reduce
来计算您的配对。
我们的想法是map
ab
数组中的值到Bool
值,取决于值是否在numbers
数组中。然后,reduce
将Bool
映射到单个值:true
,如果他们全部true
或false
。如果reduce
d值为true
,那么我们找到该对,以便我们增加计数。
var ab = [a,b] // pair to look for
var abPairApearedCount = 0
for (kind, numbers) in numberSeries {
let found = ab.map({ number in
// find is a built-in function that returns the index of the value
// in the array, or nil if it's not found
return find(numbers[0...4], number) != nil
}).reduce(true) { (result, value: Bool) in
return result && value
}
if found {
abPairApearedCount++
}
}
通过使用Swift的一些更简洁的语法,实际上可以进行相当多的压缩:
var ab = [a,b] // pair to look for
var abPairApearedCount = 0
for (kind, numbers) in numberSeries {
let found = ab.map({ find(numbers[0...4], $0) != nil }).reduce(true) { $0 && $1 }
if found {
abPairApearedCount++
}
}
而且,为了好玩,可以使用reduce
代替for-in
循环进一步压缩:
var ab = [a,b] // pair to look for
var abPairApearedCount = reduce(numberSeries, 0) { result, series in
result + (ab.map({ find(series.1[0...4], $0) != nil }).reduce(true) { $0 && $1 } ? 1 : 0)
}
虽然这种情况变得相当难以理解,但我可能会将其中的一部分扩展掉。
答案 1 :(得分:0)
所以这是我的FP解决方案,旨在将问题分解为易于消化和可重复使用的一口大小的块:
首先,我们定义一个将数组修剪为给定长度的仿函数:
func trimLength<T>(length: Int) -> ([T]) -> [T] {
return { return Array($0[0...length]) }
}
使用此功能,我们可以使用map(array, trimLength(5))
现在,我们需要一个谓词来确定一个数组的所有元素是否都在目标数组中:
func containsAll<T:Equatable>(check:[T]) -> ([T]) -> Bool {
return { target in
return reduce(check, true, { acc, elem in return acc && contains(target, elem) })
}
}
这是这里最丑陋的代码,但实际上它只是迭代检查并确保每个元素都在目标数组中。一旦我们得到了这个,我们可以使用filter(array, containsAll([7, 26]))
来消除不包含所有目标值的数组的所有元素。
此时,我们可以将整个事物粘合在一起:
filter(map(numberSeries.values, trimLength(5)), containsAll([7, 36])).count
但很长一段的嵌套函数难以阅读,让我们定义一些辅助函数和一个自定义运算符:
func rmap<S:SequenceType, T>(transform:(S.Generator.Element)->T) -> (S) -> [T] {
return { return map($0, transform) }
}
func rfilter<S:SequenceType>(predicate:(S.Generator.Element)->Bool) -> (S) -> [S.Generator.Element] {
return { sequence in return filter(sequence, predicate) }
}
infix operator <^> { associativity left }
func <^> <S, T>(left:S, right:(S)->T) -> T {
return right(left)
}
还有一个方便的功能来计算它的输入:
func count<T>(array:[T]) -> Int {
return array.count
}
现在我们可以将整个事情浓缩为:
numberSeries.values <^> rmap(trimLength(5)) <^> rfilter(containsAll([7, 36])) <^> count