Arrays 查找数组中是否存在元素序列
是否可以找到数组中是否存在元素序列? 让我们从Pi中取一些数字Arrays 查找数组中是否存在元素序列,arrays,swift,Arrays,Swift,是否可以找到数组中是否存在元素序列? 让我们从Pi中取一些数字 let piDigits=[3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,8,4,6,2,6,4,3,3,8,3,2,7,9,5,0,2,8,8,4,1,9,7,1,6,9,3,9,9,3,7,5,1,0,5,8,2,0,9,7,4,9,4,4] 现在,我想找出,5和9是否作为序列元素存在于数组中——在本例中,它们一次存在于位置4和5 理想情况下,我不希望用循环遍历数组,我希望类似于array.con
let piDigits=[3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,8,4,6,2,6,4,3,3,8,3,2,7,9,5,0,2,8,8,4,1,9,7,1,6,9,3,9,9,3,7,5,1,0,5,8,2,0,9,7,4,9,4,4]
现在,我想找出,5和9是否作为序列元素存在于数组中——在本例中,它们一次存在于位置4和5
理想情况下,我不希望用循环遍历数组,我希望类似于array.contains(元素)
@Bawpotter,代码片段:
for element in piDigits{ //check every element
if element == 5 { //if element is equal with the element i want
var currentPosition = piDigits.index(of: element) //get the position of that element
if piDigits[currentPosition!+1] == 9 { //if the element at the next position is equal to the other element i want
print("true") // it prints true 7 times, instead of 1!
}
}
}
由于没有内置的方法,这将是您最好的选择 在contains方法中,对数组进行迭代,在这里您必须执行相同的操作。这里有一个例子:
extension Array where Element: Equatable {
func contains(array elements: [Element]) -> Int {
guard elements.count > 0 else { return 0 }
guard count > 0 else { return -1 }
var ti = 0
for (index, element) in self.enumerated() {
ti = elements[ti] == element ? ti + 1 : 0
if ti == elements.count {
return index - elements.count + 1
}
}
return -1
}
}
下面是如何使用它:
let index = [1, 4, 5, 6, 6, 9, 6, 8, 10, 3, 4].contains(array: [6, 8, 10])
// index = 6
let index = [1, 4, 5, 6, 6, 9, 6, 8, 10, 3, 4].contains(array: [6, 8, 1])
// index = -1
使用线性搜索的一个非常简单的实现:
let piDigits: [Int] = [3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,8,4,6,2,6,4,3,3,8,3,2,7,9,5,0,2,8,8,4,1,9,7,1,6,9,3,9,9,3,7,5,1,0,5,8,2,0,9,7,4,9,4,4]
let searchedSequence: [Int] = [5, 9]
var index = 0
var resultIndices: [Int] = []
while index < (piDigits.count - searchedSequence.count) {
let subarray = piDigits[index ..< (index + searchedSequence.count)]
if subarray.elementsEqual(searchedSequence) {
resultIndices.append(index)
}
index += 1
}
print("Result: \(resultIndices)")
这种方法的缺点是它不会搜索重叠的范围(例如,“592”匹配两个范围,但只报告一个范围)。您可以在其子序列元素Sequal为真时过滤索引:
extension Collection where Element: Equatable {
func firstIndex<C: Collection>(of collection: C) -> Index? where C.Element == Element {
guard !collection.isEmpty else { return nil }
let size = collection.count
return indices.dropLast(size-1).first {
self[$0..<index($0, offsetBy: size)].elementsEqual(collection)
}
}
func indices<C: Collection>(of collection: C) -> [Index] where C.Element == Element {
guard !collection.isEmpty else { return [] }
let size = collection.count
return indices.dropLast(size-1).filter {
self[$0..<index($0, offsetBy: size)].elementsEqual(collection)
}
}
func range<C: Collection>(of collection: C) -> Range<Index>? where C.Element == Element {
guard !collection.isEmpty else { return nil }
let size = collection.count
var range: Range<Index>!
guard let _ = indices.dropLast(size-1).first(where: {
range = $0..<index($0, offsetBy: size)
return self[range].elementsEqual(collection)
}) else {
return nil
}
return range
}
func ranges<C: Collection>(of collection: C) -> [Range<Index>] where C.Element == Element {
guard !collection.isEmpty else { return [] }
let size = collection.count
return indices.dropLast(size-1).compactMap {
let range = $0..<index($0, offsetBy: size)
return self[range].elementsEqual(collection) ? range : nil
}
}
}
如果您在swift的标准库中寻找一些东西来实现这一点,我认为没有……如果性能至关重要,您可以使用一些特定的文本搜索算法,例如Aho Corasic。考虑数组是长文本,搜索数组是子字符串。如果性能不重要,我可能会使用一个简单的线性搜索,使用
搜索。在每个索引上检查下一个n
项是否与搜索的数组相等,如果是,则输出该索引。谢谢!我玩弄过。列举过,但显然不正确。。我也尝试过:对于piDigits中的元素{if element==5{var currentPosition=piDigits.index(of:element)if piDigits[currentPosition!+1]==9{print(“true”)}},但它不会输出正确的结果,在这种情况下,它会打印true 6次,知道为什么吗?你能编辑你原来的帖子来添加代码吗?格式化后更容易进行故障排除。嗨,Yannick,谢谢你的回答。只要不重复,您的解决方案就可以正常工作。但是如果6,8,10重复两次,它只会给我第一个的位置啊好的,你的问题不清楚。您只需询问“数组中是否存在元素序列”。如果你想拥有所有的序列,你可以在返回的数组中剪切数组,然后重新调用这个方法,直到你拥有所有的序列!我正在尝试进一步制作searchSequence数组,然后将打印结果制作成字典(不要告诉我解决方案,我想自己试试:))我试图找到一个快速版本的aho corasick,但没有成功。@Do2字符串搜索算法库并不多,因为字符串在标准库中已经有了相同的算法。算法的概念仍然有效。将输入转换为字符串,然后搜索正则表达式(subray1 | subray2 | |…)
的匹配项也是一种方法。很抱歉,我没有得到这一点。。你能给我举个例子吗?@Do2我添加了一个用于搜索子数组的正则表达式的例子。请注意,如果您自己编写算法,则可以控制边缘情况(例如重叠间隔)。
let searchedSequences: [[Int]] = [[5, 9], [7], [9, 2]]
let stringDigits = piDigits.map { String($0) }.joined()
let stringSearchedSequences = searchedSequences.map { sequence in sequence.map { String($0) }.joined() }
let regularExpressionPattern = stringSearchedSequences.joined(separator: "|")
let regularExpression = try! NSRegularExpression(pattern: regularExpressionPattern, options: [])
let matches = regularExpression.matches(in: stringDigits, options: [], range: NSRange(location: 0, length: stringDigits.characters.count))
let matchedIndices = matches.map { $0.range.location }
print("Matches: \(matchedIndices)")
extension Collection where Element: Equatable {
func firstIndex<C: Collection>(of collection: C) -> Index? where C.Element == Element {
guard !collection.isEmpty else { return nil }
let size = collection.count
return indices.dropLast(size-1).first {
self[$0..<index($0, offsetBy: size)].elementsEqual(collection)
}
}
func indices<C: Collection>(of collection: C) -> [Index] where C.Element == Element {
guard !collection.isEmpty else { return [] }
let size = collection.count
return indices.dropLast(size-1).filter {
self[$0..<index($0, offsetBy: size)].elementsEqual(collection)
}
}
func range<C: Collection>(of collection: C) -> Range<Index>? where C.Element == Element {
guard !collection.isEmpty else { return nil }
let size = collection.count
var range: Range<Index>!
guard let _ = indices.dropLast(size-1).first(where: {
range = $0..<index($0, offsetBy: size)
return self[range].elementsEqual(collection)
}) else {
return nil
}
return range
}
func ranges<C: Collection>(of collection: C) -> [Range<Index>] where C.Element == Element {
guard !collection.isEmpty else { return [] }
let size = collection.count
return indices.dropLast(size-1).compactMap {
let range = $0..<index($0, offsetBy: size)
return self[range].elementsEqual(collection) ? range : nil
}
}
}
[1, 2, 3, 1, 2].indices(of: [1,2]) // [0,3]
[1, 2, 3, 1, 2].ranges(of: [1,2]) // [[0..<2], [3..<5]]
extension Collection where Element: Equatable {
func contains<C: Collection>(_ collection: C) -> Bool where C.Element == Element {
guard !collection.isEmpty else { return false }
let size = collection.count
for i in indices.dropLast(size-1) where self[i..<index(i, offsetBy: size)].elementsEqual(collection) {
return true
}
return false
}
}
[1, 2, 3].contains([1, 2]) // true