当我对数组中的某个项目进行引用时,我想找到一个与其最接近的符合特定条件(向前或向后)的项目。
例如,我有这个数组:
// If the 'a' or 'b'are present in string, it returns the index(>=0).
//If not, it returns -1. So, a non-negative return value means that 'a' is
// present in the string.
private boolean checkText(String string) {
final int aIndex = string.indexOf('a');
final int bIndex = string.indexOf('b');
if (aIndex!=-1 && bIndex!=-1) {
return true;
}
else {
return false;
}
}
现在说我有let items = [
(a: "Item 1", b: "F", c: 3),
(a: "Item 2", b: "S", c: 5),
(a: "Item 3", b: "D", c: 7),
(a: "Item 4", b: "A", c: 9),
(a: "Item 5", b: "M", c: 11),
(a: "Item 6", b: "I", c: 13),
(a: "Item 7", b: "F", c: 15),
(a: "Item 8", b: "S", c: 17),
(a: "Item 9", b: "D", c: 19),
(a: "Item 10", b: "A", c: 21),
(a: "Item 11", b: "M", c: 23),
(a: "Item 12", b: "I", c: 13),
(a: "Item 13", b: "F", c: 15),
(a: "Item 14", b: "S", c: 17),
(a: "Item 15", b: "D", c: 19),
(a: "Item 16", b: "A", c: 21),
(a: "Item 17", b: "M", c: 23),
(a: "Item 18", b: "I", c: 13),
(a: "Item 19", b: "F", c: 15),
(a: "Item 20", b: "S", c: 17),
(a: "Item 21", b: "D", c: 19),
(a: "Item 22", b: "A", c: 21),
(a: "Item 23", b: "M", c: 23),
(a: "Item 24", b: "I", c: 13)
]
,如何找到最近的项item[7]
?我只能想到几个嵌套的for循环,但听起来很乱,而且性能不好。另外请记住,我不想在搜索时遇到b = "I"
问题。关于如何处理这个问题的任何类似Swift的想法?
答案 0 :(得分:1)
假代码:
int index = 7;
int delta = 0;
while (true)
{
delta = delta + 1;
if ( index - delta >= 0 && matches(items[ index - delta]) {
// Found closest index on Left : index-delta
break;
}
if ( index + delta < items.length && matches(items[ index + delta]) {
// Found closest index on Right: index + delta
break;
}
}
// Time complexity: O(N)
您可以轻松地将假代码转换为Swift代码。
答案 1 :(得分:1)
以下是关于Array的通用,它应该可以满足您的需求。它返回一个包含索引和最接近匹配值的元组:
extension Array {
func closestMatch(index:Index, predicate:(Element)->Bool) -> (Int, Element)? {
if predicate(self[index]) {
return (index, self[index])
}
var delta = 1
while(true) {
guard index + delta < count || index - delta >= 0 else {
return nil
}
if index + delta < count && predicate(self[index + delta]) {
return (index + delta, self[index + delta])
}
if index - delta >= 0 && predicate(self[index - delta]) {
return (index - delta, self[index - delta])
}
delta = delta + 1
}
}
}
print(items.closestMatch(7) { $0.1 == "I" })
答案 2 :(得分:1)
除了其他解决方案之外,还有“一线”:
let index = 7
let searchString = "I"
let result = items.enumerate()
.filter { $0.1.b == searchString }
.map { (abs(index - $0.0), $0.1) }
.minElement { $0.0 < $1.0 }
.map { $0.1 }
print(result) // Optional(("Item 6", "I", 13))
根据David Berry的回答:
extension Array {
func closestMatch(index: Index, predicate: (Element) -> Bool) -> Element? {
return enumerate().filter { predicate($0.1) }.map { (abs(index - $0.0), $0.1) }.minElement { $0.0 < $1.0 }.map { $0.1 }
}
}
print(items.closestMatch(7) { $0.1 == "I" }) // Optional(("Item 6", "I", 13))
注意:强> 性能方面,David Berry的答案更好。
答案 3 :(得分:0)
此功能应该有效:
func findClosestItem(index: Int, items: [(a: String, b: String, c: Int)]) -> (a: String, b: String, c: Int)? {
guard index < items.count && index > -1 else{
return nil
}
var foundItem: (String, String, Int)? = nil
var closestBefore = Int(INT16_MAX)
for i in (index - 1).stride(to: 0, by: -1) {
if items[index].b == items[i].b {
closestBefore = index - i
foundItem = items[i]
break
}
}
var closestAfter = Int(INT16_MAX)
for i in index + 1 ..< items.count {
if items[index].b == items[i].b {
closestAfter = i - index
if closestAfter < closestBefore {
foundItem = items[i]
}
break
}
}
return foundItem
}
如果没有其他匹配项目或者它是无效索引,它将返回nil,否则它将返回该项目。
它只是搜索回来,直到找到匹配的项目,然后向前搜索,直到找到匹配的项目,并返回最接近的项目。
答案 4 :(得分:0)
最简单的是:
let startIndex = 7
if startIndex < items.count,
let nextIndex = items[startIndex+1..<items.endIndex].indexOf({ $0.b == items[startIndex].b }) {
print(items[nextIndex]) // => "("Item 14", "S", 17)\n"
}
这不是问题的完整答案,只是一种进行前向搜索的方法的示例。我意识到它与我发布后的内容不符,但我会把它作为一个部分示例。
答案 5 :(得分:0)
使用高阶函数的优化解决方案:
func closestMatch(values: [Int64], inputValue: Int64) -> Int64? {
return (values.reduce(values[0]) { abs($0-inputValue) < abs($1-inputValue) ? $0 : $1 })
}
Swift正在与每个版本一起前进,以优化性能和效率。使用此函数,使用高阶函数查找值数组中最接近的匹配要容易得多。根据需要更改值的类型。