在另一个数组中查找一个数组的值范围

时间:2017-01-17 13:11:24

标签: arrays swift find range

我在SWIFT中有一个数组

let a = [0.0, 0.00250, 0.0050, 0.00749, 0.01, 0.01251, 0.01499, 0.0175, 0.02, 0.022, 0.025] // is always a sequence (increasing)

我还有第二个数组

let b = [0.0, 0.004, 0.008, 0.012, 0.016, 0.02, 0.024, 0.028, 0.032, 0.036, 0.04, 0.044, 0.048, 0.052, 0.056] // is always a sequence (increasing)

我必须找到“b”的所有元素,即> = a [0]& < = a [a.count-1]并用这些值填充向量“c”。

那样

let c = [0.0, 0.004, 0.008, 0.012, 0.016, 0.02, 0.024] // ANSWER

最有效的方法是什么?

4 个答案:

答案 0 :(得分:1)

由于您知道两个序列都在增加,因此您只需要使用数组a的第一个和最后一个元素。使用这些方法,您可以使用index(where:)方法在b数组中查找相应的索引,从而完成谓词>= (first of a)<= (last of a)。 E.g。

if let aFirst = a.first, let aLast = a.last,
   let startIndex = b.index(where: { $0 >= aFirst }),
   case let endIndex = b.index(where: { $0 > aLast }) ?? a.endIndex {
    let c = b[startIndex..<endIndex] // note: this is an ArraySlice<Double>
                                     // wrap in Array(..) to construct a new array
    print(c) 
       // [0.0, 0.0040000000000000001, 0.0080000000000000002, 0.012, 0.016, 0.02, 0.024]
}

或者,正如@MartinR所提议的那样,我们可以猜测,如果我们从index(where:)的末尾开始,我们将会更快地完成第二次b调用的谓词。检查满足$0 <= aLast条件的第一个元素:

if let aFirst = a.first, let aLast = a.last,
   let startIndex = b.index(where: { $0 >= aFirst }),
   case let endIndex = b.reversed().index(where: { $0 <= aLast })!.base {
                    /* ^^^^^- as proposed by @MartinR */
    let c = b[startIndex..<endIndex]
    print(c) 
       // [0.0, 0.0040000000000000001, 0.0080000000000000002, 0.012, 0.016, 0.02, 0.024]
}

最后,此方法(以及当前可用的其他答案中的filter方法)在O(n)中运行。一种更高效的方法是使用二进制搜索,它在O(log n)渐近运行。正如@MartinR所提到的,一个很好的起点可能是Rosetta代码中的二进制搜索Swift实现:

如本Q&amp; A中所述:

回答评论:

  

......我还有另外一个我忘记提及的问题。我还有一个   数组yb具有完全相同的元素数。我们可以   将这些视为信号的XY值。我必须选择   我在y中选择的元素匹配来自b的元素。

最简单的解决方案只是应用计算出的startIndexendIndex来切出y数组的一部分(就像你将b的一部分切成一样构建c)。

let d = y[startIndex..<endIndex] 
// assumes y.count == b.count, and that these are not slices
// with non-matching indices

但是,我认为更好的方法是使用zip。只需压缩yb并使用结果构建一个元组数组,然后您可以将上面的谓词应用于压缩序列的b成员:

let y = Array(1...b.count)

if let aFirst = a.first, let aLast = a.last,
   let startIndex = bAndY.index(where: { $0.0 >= aFirst }),
   case let endIndex = bAndY.index(where: { $0.0 > aLast }) ?? a.endIndex {
    let cAndD = bAndY[startIndex..<endIndex]
    print(cAndD)
        /* [(0.0040000000000000001, 2),
            (0.0080000000000000002, 3), 
            (0.012,                 4), 
            (0.016,                 5),
            (0.02,                  6), 
            (0.024,                 7)] */
}

自然地构造cAndD数组会产生一些小的开销,但除非你编写一些真正的HPC应用程序,否则你不必担心这一点。

答案 1 :(得分:0)

您可以在阵列上使用filter函数,它将返回一个新数组。您可以比较值是&gt; = a [0]还是&lt; = a [a.count-1]。显然,您应该始终检查数组是否包含多于0个元素。

let smallestValue = a[0]
let highestValue = a[a.count-1]

let c = b.filter() { return smallestValue <= $0 && $0 <= highestValue }

计算索引

因为b总是增加固定量,例如0.004在你的情况下,你可以计算你的指数。这非常有效,因为您只进行了两次比较,最多两次计算非常快。

let smallestValueA = a[0]
let highestValueA = a[a.count-1]
let smallestValueB = b[0]
let highestValueB = b[b.count-1]
let increase = 0.004 //based on your example
var smallestIndex: Int = 0
var highestIndex: Int = b.count

if smallestValueA > smallestValueB {
    smallestIndex = Int((smallestValueA - smallestValueB) / increase).rounded(.up)
}

if highestValueA < highestValueB {
    highestIndex = Int(((highestValueB - highestValueA) - smallestValueB) / increase)
}

let c = b[smallestIndex..<highestIndex] //[0.0, 0.0040000000000000001, 0.0080000000000000002, 0.012, 0.016, 0.02, 0.024]

答案 2 :(得分:0)

另一种方法是:

let c = b.filter() { return (a.first)! <= $0 && $0 <= (a.last)! }

答案 3 :(得分:-1)

您不应将值保存为数组。

如果彼此不相等,

保存一组并使用

let c = a.intersection(b)

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html