【问题标题】:How do I sort a 2 dimensional array columns in Swift based on the values in a row?如何根据一行中的值对 Swift 中的二维数组列进行排序?
【发布时间】:2019-05-24 12:03:06
【问题描述】:

如何根据其中一行中的值对二维数组进行排序?

let array = [["X", "Y",   1,  2,  3,  4,  5],
             ["V", "W", "A","B","C","D","E"]
]

let sorted = [["X", "Y",   5,  4,  3,  2,  1],
              ["V", "W", "E","D","C","B","A"]
    ]

Swift Array.sort({e1, e2 in e1 < e2}) 传入行元素,而不是列元素。

更糟糕的是,不能对行中的前两列进行排序。

请记住,第 2 行必须根据第 1 行的顺序重新排列。所以假设我们按第 0 行排序并忽略第 2 列

[["X", "Y",   1,  2,  3,  4,  5],
 ["V", "W", "E","B","A","D","F"]]

应该变成

[["X", "Y",   5,  4,  3,  2,  1],
 ["V", "W", "F","D","A","B","E"]]

【问题讨论】:

  • 不了解您要用于获取排序数组的逻辑。请解释一下。

标签: arrays swift sorting


【解决方案1】:

首先映射数组元素并从子数组中拆分前 2 个元素以跳过排序。现在使用开关模式匹配对剩余元素进行排序。然后将排序后的数组与前 2 个元素连接起来。

let array = [["X", "Y",   1,  2,  3,  4,  5],
             ["V", "W", "A","B","C","D","E"]]

let sorted = array.map { $0[..<2] + $0[2...].sorted(by: {
    switch ($0,$1) {
    case (let a as Int, let b as Int): return a > b
    case (let a as String, let b as String): return a > b
    case (let a as Date, let b as Date): return a > b
    case (_, _): return false
    }
})}.map { Array($0) }
print(sorted)

[["X", "Y", 5, 4, 3, 2, 1], ["V", "W", "E", "D", "C", "B", " A"]]

【讨论】:

  • 哇——我会在操场上测试一下。请记住,第 2 行必须根据第 1 行的顺序重新排列。所以 [["X", "Y", 1, 2, 3, 4, 5], ["V", "W", "E","B","A","D","F" ]] 应该变成 [["X", "Y", 5, 4, 3, 2, 1], ["V", "W", "F","D","A","B", "E"]]
  • @DuncanGroenewald 否。现在第二个数组单独排序。我会更新答案
  • 我发现我必须用排序的行数据和索引创建一个新结构,然后对这个结构的数组进行排序,然后使用随后的排序数组找到必须要排序的列的索引被移动到新的位置。毫无疑问,有一种更简单的方法。
  • @DuncanGroenewald 是的。使用结构更容易
【解决方案2】:

这是我想出的解决方案 - 非常丑!!

extension Array where Element == Array<String> {
    /// Creates a totals row at the bottom
    /// ignore - number of columns to ignore at the start
    mutating func addTotalsRow(ignore: Int){
        // Create a totals row (top row)
        var totals = [String]()
        // Add columns if required
        if ignore > 0 {
            totals.append("Total")
            totals.append(contentsOf: repeatElement("", count: ignore - 1))

        }


        for row in self {
            for i in ignore..<row.count {

                let value = row[i].toDouble ?? 0.0
                if (i+1) > totals.count {
                    totals.append("0.0")
                }
                totals[i] = ((totals[i].toDouble ?? 0.0) + value).formatted4
            }
        }

        self.append(totals)

        return
    }

    /// Sort columnwise using values in 'row', ignoring first 'ignore' columns
    /// Also sorts the optional header row
    /// Returns (sortedRows, sortedHeaderRow)
    func columnSorted(_ sortRow: Int, ignoreColumnCount: Int, order: SortOrder = .ascending, headerRow: [String]?)->([[String]], [String]?) {

        // Now calculate a totals row
        var newHeader: [String]?

        // Create an array of objects holding the total and the column index
        var indexes = [IX]()

        let totals = self[sortRow]

        // Ignore the text columns
        for i in ignoreColumnCount..<totals.count {
            indexes.append(IX(total: totals[i], index: i))
        }
        // Sort IX by the totals
        indexes.sort(by: {ix1, ix2 in
            return order == .descending ? ix1.intTotal > ix2.intTotal : ix1.intTotal < ix2.intTotal})

        // Create the Totals data row
        var totalsRow = [String]()
        totalsRow.append(contentsOf: totals[0..<ignoreColumnCount])
        totalsRow.append(contentsOf: indexes.map({$0.total}))



        if let header = headerRow {
            newHeader = [String]()
            newHeader!.append(contentsOf: header[0..<ignoreColumnCount])
            for i in 0..<indexes.count {
                let ix = indexes[i].index
                if ((i+ignoreColumnCount)+1) > newHeader!.count {
                    newHeader!.append("")
                }
                newHeader![i+ignoreColumnCount] = header[ix]
            }
        }

        var newData = [[String]]()
        // newData.append(totalsRow)
        // Now do the same for all the rows in data
        for row in self {
            var newRow = [String]()
            newRow.append(contentsOf: row[0..<ignoreColumnCount])

            for i in 0..<indexes.count {
                let ix = indexes[i].index
                if ((i+ignoreColumnCount)+1) > newRow.count {
                    newRow.append("0.0")
                }
                newRow[i+ignoreColumnCount] = row[ix]
            }
            newData.append(newRow)
        }

        // Sort by count
        return (newData, newHeader)
    }
    /// Sort by column index 0...
    mutating func sort(by column: Int, order: SortOrder = .ascending) {

        guard column > 0 else {
            return
        }
        let index = column - 1

        self.sort(by: {r1, r2 in
            let count1 = (r1[index].toDouble ?? 0.0)
            let count2 = (r2[index].toDouble ?? 0.0)
            if let val = r1[index].toDouble {
                return order == .descending ? (r1[index].toDouble ?? 0.0) > (r2[index].toDouble ?? 0.0) : (r1[index].toDouble ?? 0.0) < (r2[index].toDouble ?? 0.0)
            } else {
                return order == .descending ? r1[index] > r2[index] : r1[index] > r2[index]
            }
        })
    }

    func sorted(by column: Int, order: SortOrder = .ascending, ignoreFirstRow: Bool = false)->[[String]] {

        guard column > 0 else {
            return self
        }
        let index = column - 1

        var resultSet = [[String]]()

        if ignoreFirstRow {
            // Save the first row
            let firstRow = self[0]

            let dataRows = self[1..<count].sorted(by: {r1, r2 in

                if let val = r1[index].toDouble {
                    return order == .descending ? (r1[index].toDouble ?? 0.0) > (r2[index].toDouble ?? 0.0) : (r1[index].toDouble ?? 0.0) < (r2[index].toDouble ?? 0.0)
                } else {
                    return order == .descending ? r1[index] > r2[index] : r1[index] < r2[index]
                }

            })
            resultSet.append(firstRow)
            resultSet.append(contentsOf: dataRows)
        } else {

            let dataRows = self[0..<count].sorted(by: {r1, r2 in

                if let val = r1[index].toDouble {
                    return order == .descending ? (r1[index].toDouble ?? 0.0) > (r2[index].toDouble ?? 0.0) : (r1[index].toDouble ?? 0.0) < (r2[index].toDouble ?? 0.0)
                } else {
                    return order == .descending ? r1[index] > r2[index] : r1[index] < r2[index]
                }

            })
            resultSet.append(contentsOf: dataRows)
        }

        return resultSet
    }
    func printArray(){
        for row in self {
            print("\(row)")
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-17
    • 2015-06-08
    • 2015-08-25
    • 2021-06-24
    • 1970-01-01
    相关资源
    最近更新 更多