Swift - Sort Array с несколькими сравнениями - PullRequest
0 голосов
/ 04 июля 2018

Моя проблема довольно проста:

  • У меня много данных в базе данных (кстати, я использую Firebase)
  • Я хотел бы получить эти оценки (это легко) и отсортировать их (менее легко)

Если пользователь закончит тренировку, он введет свое время, если нет, он введет номер или повторения.

Проще говоря, объект результата выглядит так:

Result
 |_ resultValue (Int) // It can be time in seconds or number of reps
 |_ isFinished (Int) // It can be 0 (not finished) or 1 (finished)

Я бы хотел отсортировать массив результатов следующим образом:

  1. Первое: все результаты с isFinished == 1 выше, чем остальные
  2. Тогда: сортировать результаты, где isFinished == 1 по resultValue DESC
  3. Наконец: сортировка результатов, где isFinished == 0 по значению результата ASC

Я пробовал что-то подобное:

self.results = self.results.sorted {
 ($0.result.isForTimeFinished!, $0.result.resultValue!) > 
 ($1.result.isForTimeFinished!, $1.result.resultValue!)
}

Таким образом, результаты тренировки не завершены, после того, как результаты тренировки завершены, но "Сортировать результаты, где isFinished == 1 по resultValue DESC" не в порядке ...

Вы знаете, как я мог бы объединить все это?

Ответы [ 3 ]

0 голосов
/ 04 июля 2018

Попробуйте это:

self.results = self.results.sorted {
    if $0.result.isForTimeFinished != $1.result.isForTimeFinished {
        return $0.result.isForTimeFinished > $1.result.isForTimeFinished
    }
    else if $0.result.isForTimeFinished == 0 {
        return $0.result.resultValue > $1.result.resultValue
    }
    else {
        return $0.result.resultValue < $1.result.resultValue
    }
}

Примечание: я мог бы получить знаки наоборот, но немного поиграть

0 голосов
/ 04 июля 2018

Logical OR останавливается при первой TRUE оценке, поэтому нет необходимости оценивать следующее выражение. Есть 3 правила, когда $0 должно быть выше $1 в списке, попробуйте следующее:

self.results = self.results.sorted {
    let b0 = $0.result.isForTimeFinished!
    let b1 = $1.result.isForTimeFinished!
    let v0 = $0.result.resultValue!
    let v1 = $1.result.resultValue!
    // $0 will be above $1 in the list if returning true, otherwise it will be listed lower
    return 
        b0 && !b1 // is finished > not finished
        ||
        b0 && b0 == b1 && v0 < v1 // both finished, higher value
        ||
        !b0 && b0 == b1 && v0 > v1 // both not finished, lower value
}
0 голосов
/ 04 июля 2018

Лично я бы добавил вычисленную var к вашей модели результатов, называемую как searchScore, которая будет вычислена (хотя я не совсем достигаю вашей цели, но похоже, что в основном вы разбиваете ваши данные на 3 слоя) а затем играть с восходящим / нисходящим), который вы могли бы затем просто выполнить сортировку.

Так что-то вроде этого

class Result {
...
    var searchScore: Double {
       return *ALGORITHM FOR SCORE*
    }
}
let sorted = results.sorted {$0.searchScore < $0.searchScore}

Настоящим плюсом этого подхода является поддержание чистоты кода и отсутствие необходимости понимать, как упорядочить вещи в неправильном месте.

...