在iOS中对包含字符串范围的数组进行排序

3

我在sqlite数据库中有一系列的数据,格式如下屏幕截图所示。

enter image description here

我已将所有这些值存储在一个字符串数组中。现在,我需要对数组中的对象进行排序,使结果如下,并在表格视图中显示。

<10厘米

90 - 130厘米

240 - 300厘米

400 - 600厘米

'>700厘米

我尝试了一些代码。

示例代码1:

 var arr = ["240 - 300 cm", "400 - 600 cm ", "90 - 130 cm", "<10 cm", ">700 cm"]
 var arr1 = arr.sorted{$0 < $1}

然而,这种方法似乎对包含字母数字字符的字符串有效。因此,我尝试了另一种方法。

示例代码2:

var arr1 = [NSValue.init(range: NSMakeRange(240, 300)), NSValue.init(range: NSMakeRange(400, 600)), NSValue.init(range: NSMakeRange(90, 130))]
var arr2 = arr1.sorted{$0.rangeValue.location < $1.rangeValue.location}

for range in arr2 {
    print("\(range.rangeValue.location) - \(range.rangeValue.length) cm")
}

但是,为了使这种方法起作用,我必须执行以下操作:

  • 根据要求以格式(例如90-130厘米)操纵数据,以便我可以混合它以适应NSRange。

  • 对于像<10厘米和>700厘米这样的值,我必须单独处理。也许,在数组排序后将这些值插入第一个索引和最后一个索引,但还没有尝试过。

  • 在数组排序后,再次以适当的格式打印该值,我已经使用上面示例代码中的for循环完成了此操作。

这种方法似乎可以工作,但需要付出大量时间和操作的代价。如果有100行这样的数据,我不知道性能如何。

我的问题是,是否有更好且简明的方法在iOS中按范围格式对数据进行排序?

非常感谢任何帮助。


问题:如果字符串以“<”开头,是否意味着它在排序后始终是第一个元素?同样地,如果以“>”开头,是否意味着它应该始终是排序后的最后一个元素? - Ahmad F
是的,@Ahmad F,我查看了更多这种范围数据的示例,我非常确定在小于(<)运算符之前和大于(>)运算符之后不会有任何数据。它们代表列表的最小和最大限制。 - skJosh
3个回答

2

此解决方案检查字符串的第一个字符。如果它可以转换为Int,则使用整个字符串,否则删除第一个字符并使用剩余部分。然后执行常规的compare排序,选项为numeric

let arr = ["240 - 300 cm", "400 - 600 cm ", "90 - 130 cm", "<10 cm", ">700 cm"]

let arr1 = arr.sorted { (str1, str2) -> Bool in
    let lhs = Int(str1.prefix(1)) == nil ? String(str1.dropFirst()) : str1
    let rhs = Int(str2.prefix(1)) == nil ? String(str2.dropFirst()) : str2
    return rhs.compare(lhs, options: .numeric) == .orderedDescending
}

print(arr1)

1

虽然可能不是最优雅的解决方案,但您可以通过检查每个字符串的第一个元素来实现所需的排序:

var arr = ["240 - 300 cm", "400 - 600 cm ", "90 - 130 cm", "<10 cm", ">700 cm"]

func sortMyArray(_ array: [String]) -> [String] {
    var lessThanElements = [String]()
    var defaultPatternElements = [String]()
    var greaterThanElements = [String]()

    for srting in array {
        switch srting.first! {
        case "<":
            lessThanElements.append(srting)
        case ">":
            greaterThanElements.append(srting)
        default:
            defaultPatternElements.append(srting)
        }
    }

    return lessThanElements.sorted() + defaultPatternElements.sorted() + greaterThanElements.sorted()
}

let sortedArray = sortMyArray(arr)
print(sortedArray) // ["<10 cm", "240 - 300 cm", "400 - 600 cm ", "90 - 130 cm", ">700 cm"]

请注意,如果字符串的第一个字符不是“<”或“>”,它将被视为defaultPatternElements元素。

不错的尝试。谢谢。 - skJosh

1
我认为如果你只有100条这样的记录,那么创建一个缓慢的算法将非常困难。你几乎可以做任何想做的事情,但不会意识到性能影响——至少不是在毫秒级别上。
如果你有大量的数据,并且经常进行排序(例如,排序的频率高于数据更改的频率),一种解决方案是对数据库进行去规范化:
- 创建一个单独的行"normalizedLength"或其他名称 - 解析所有数据,将类似"90 - 130 cm"的内容转换为整数值"90"并存储到"normalizedLength"中 - 对于"> ..."和"< ..."的值使用"Int.max"和"Int.min"
这必须对所有数据进行一次操作。然后,您可以多次进行排序等操作。

你的意思是创建一个单独的列normalizedLength,将下限例如90存储在数据90-130旁边的列中,并根据normalizedLength进行排序。 - skJosh
是的。由于范围不重叠(我猜),只有下限是相关的。 - Andreas Oetjen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接