Свифт рейтинг словарь - PullRequest
1 голос
/ 09 июня 2019

Я могу ранжировать словарь строк и int.Но мое решение не выглядит умным и «быстрым»

Проблема в том, что больше команд имеют одинаковые очки и одинаковый ранг с «командой 2» и «командой 4»

исходный ввод

var dict:[String:Int] = ["team1":79,"team2":5, "team3":18, "team4":5, "team5": 82, "team6":1]

вывод

[(команда: «team5», ранг: 1), (команда: "team1", ранг: 2), (команда: "team3", ранг: 3), (команда: "team2", ранг: 4), (команда: "team4", ранг: 4), (команда: "team6 ", ранг: 5)]

код:

var ris = [(team:String,rank:Int)]()
var pos = 1

let sorted = dict.sorted(by:{$0.value > $1.value})
print(sorted)
for (i, element) in sorted.enumerated() {

    if i == 0 ||  element.value == sorted[i-1].value {

    }
    else {
        pos += 1
    }
    ris.append((team:element.key,rank:pos))
}
let ranking = ris.sorted(by:{$0.rank < $1.rank})
print(ranking)

отпечатки:

[(команда:" team5 ", ранг:1), (команда: «team1», ранг: 2), (команда: «team3», ранг: 3), (команда: «team2», ранг: 4), (команда: «team4», ранг: 4), (команда: "team6", ранг: 5)]

хорошо, это работает, но я уверен, что я пропускаю что-то лучшее, используя некоторое закрытие отсортированных карт, флапмапов и т. д.

любой

Ответы [ 2 ]

2 голосов
/ 09 июня 2019

Вы можете немного упростить это, сгруппировав команды с одинаковыми баллами в словаре. Затем отсортируйте словарь (по убыванию оценки), перечислите его (чтобы получить смещения) и составьте список рейтинга:

let dict:[String:Int] = ["team1":79, "team2":5, "team3":18, "team4":5, "team5": 82, "team6": 1]

let ranking = Dictionary(grouping: dict, by: { $0.value })
    .sorted(by: { $0.key > $1.key })
    .enumerated()
    .flatMap { (offset, elem) in
        elem.value.map { (team: $0.key, rank: offset + 1 )}
    }

print(ranking)
// [(team: "team5", rank: 1), (team: "team1", rank: 2),
//  (team: "team3", rank: 3), (team: "team2", rank: 4),
//  (team: "team4", rank: 4), (team: "team6", rank: 5)]]

Подробное объяснение:

Dictionary(grouping: dict, by: { $0.value })

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

.sorted(by: { $0.key > $1.key })

сортирует словарь по убыванию ключей, в результате получается массив кортежей:

 [(key: 82, value: [(key: "team5", value: 82)]),
  (key: 79, value: [(key: "team1", value: 79)]),
  (key: 18, value: [(key: "team3", value: 18)]),
  (key: 5, value: [(key: "team2", value: 5), (key: "team4", value: 5)]),
  (key: 1, value: [(key: "team6", value: 1)])]

Тогда

.enumerated()

создает ленивую последовательность пар (смещение, элемент) из этого массива:

  (offset: 0, element: (key: 82, value: [(key: "team5", value: 82)])),
  (offset: 1, element: (key: 79, value: [(key: "team1", value: 79)])),
  (offset: 2, element: (key: 18, value: [(key: "team3", value: 18)])),
  (offset: 3, element: (key: 5, value: [(key: "team2", value: 5), (key: "team4", value: 5)])),
  (offset: 4, element: (key: 1, value: [(key: "team6", value: 1)]))

Наконец, flatMap вызывает замыкание для каждой пары (смещение, элемент) и объединяет результат. Внутри закрытия,

 elem.value.map { (team: $0.key, rank: offset + 1 )}

отображает пару (смещение, элемент) и массив (команда, ранг) кортежей. Например,

  (offset: 3, element: (key: 5, value: [(key: "team2", value: 5), (key: "team4", value: 5)]))

отображается на

 [(team: "team2", rank: 4), (team: "team4", rank: 4)]

flatMap() объединяет эти массивы, давая окончательный массив ranking.


Это первоначально опубликованное решение, которое выдает ранги 1, 2, 3, 4, 4, 6 для выборочных данных (вместо 1, 2, 3, 4, 4, 5):

let dict:[String:Int] = ["team1":79, "team2":5, "team3":18, "team4":5, "team5": 82, "team6": 1]

var ranking = [(team:String,rank:Int)]()
for (_, list) in Dictionary(grouping: dict, by: { $0.value })
    .sorted(by: { $0.key > $1.key }) {
        let pos = ranking.count + 1
        ranking.append(contentsOf: list.map { ($0.key, pos )})
}

print(ranking)
// [(team: "team5", rank: 1), (team: "team1", rank: 2),
//  (team: "team3", rank: 3), (team: "team4", rank: 4),
//  (team: "team2", rank: 4), (team: "team6", rank: 6)]
1 голос
/ 09 июня 2019

Да, есть гораздо более простое решение:)

let teamScores = [
    "team1":79,
    "team2":5,
    "team3":18,
    "team4":5,
    "team5": 82
]

let teamRanks = teamScores
    .sorted(by: { $0.value > $1.value})
    .enumerated()
    .map { (offset: Int, pair: (team: String, score: Int)) -> (team: String, rank: Int) in
        let rank = offset + 1
        return (team: pair.team, rank: rank)
    }

print(teamRanks)
  • Вы сортируете результаты команд так, чтобы наивысшие оценки были на первом месте
  • Перечислите последовательность, чтобы иметь доступк индексам (где 0 - лучшая команда, 1 - вторая лучшая команда, ...)
  • Сопоставить элементы переименовать элементы кортежа и добавить один ко всем смещениям (которые образуют1 на основе индексов)

Если вы хотите, чтобы связанные оценки получили одинаковый ранг, тогда сигнатуры типов становятся немного более пугающими, но идея похожа:

let teamScores = [
    "team1":79,
    "team2":5,
    "team3":18,
    "team4":5,
    "team5": 82
]

let teamRanks = Dictionary(grouping: teamScores, by: { $0.value })
    .sorted(by: { $0.key > $1.key })
    .enumerated()
    .flatMap { (
        offset: Int,
        ranks: (
            commonScore: Int,
            teamScores: [(key: String, value: Int)]
        )
    ) -> [(team: String, rank: Int)] in
        let rank = offset + 1
        return ranks.teamScores.map { (team: $0.key, rank: rank) }
    }

print(teamRanks)
...