Как отсортировать карту в Go на основе ключевых значений другой карты?

# #algorithm #sorting #dictionary #go #hashmap

Вопрос:

Мне нужно отсортировать карту на основе ключей другой карты, потому что моя текущая функция, возвращающая карту, не отсортирована, поэтому мне нужно, чтобы она была согласованной на основе этого порядка имен, как показано в reference . Я знаю о некоторых функциях сортировки, однако у меня возникли некоторые проблемы с их реализацией. Повторяю, мне нужно, чтобы имена были отсортированы так же, как reference и переменная; никакого алфавитного порядка, основанного только на одном конкретном порядке карт. Было бы здорово, если бы кто-нибудь мог, пожалуйста, помочь с этим.

Чтобы уточнить, мне нужно отсортировать возвращаемые значения из testMap() и testMap2() в том же порядке, reference что и . reference Переменная показывает связь между двумя именами (разница в соглашениях об именовании).

 package main

import (
    "fmt"
)

var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
    testMap() 
}

func testMap() map[string]int {
    return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

func testMap2() map[string]int {
    return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}
 

Комментарии:

1. Поскольку ключи карт не имеют определенного порядка, невозможно отсортировать карту или определить порядок карты. Какова проблема более высокого уровня, которую вы пытаетесь решить? Возможно, существует хорошее решение этой проблемы.

2. Я понимаю. Вот что я пытаюсь решить: у меня есть две карты с похожими данными, однако ключи имеют разные имена, поэтому, например, на первой карте первый ключ-это Ali, но на другой карте он называется Ali1 или Ali_someString (поэтому у меня нет возможности отсортировать это каким-либо особым способом, кроме ссылки на предопределенную карту. Я хочу получить две карты и отсортировать их в одинаковом порядке на основе ссылочной переменной, как показано в фрагменте кода.

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

4. @HenryWoody Я считаю, что это то, что я пытаюсь сделать (я обновил вопрос), однако я не смог до конца понять это. Не могли бы вы показать мне пример того, как это сделать в Go, пожалуйста?

5. Отредактированный вопрос по-прежнему предполагает, что карты имеют порядок. Это проблема XY ? Поднимитесь на уровень выше и опишите проблему, которую вы пытаетесь решить, сортируя карты.

Ответ №1:

Предварительная записка

Чтобы повторить кое-что важное из комментариев: карты в Go не имеют определенных заказов, и поэтому вы не можете сортировать их или гарантировать их порядок.

С карты Go в действии:

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


Ответ

Вы можете выполнить итерацию по ключам/значениям reference и получить значение из первой и второй карты, используя первый и второй ключ.

 package main

import (
    "fmt"
)

var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
    m1 := testMap()
    m2 := testMap2()

    for key1, key2 := range reference {
        v1, _ := m1[key1]
        v2, _ := m2[key2]
        fmt.Printf("%s/%s: (%d, %d)n", key1, key2, v1, v2)
        // not sure what you want with these, so I'm just printing
    }
}

func testMap() map[string]int {
    return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

func testMap2() map[string]int {
    return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

 

Обратите внимание, что это все еще не гарантирует порядок, только то, что значения для «совпадающих» ключей сопоставлены.

Если вы хотите заказать, вам понадобится что-то, что имеет порядок (например, кусочек). Например:

 package main

import (
    "fmt"
)

var keyOrder = []string{"Ali", "Cat", "Bob"}
var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
    m1 := testMap()
    m2 := testMap2()

    for _, key1 := range keyOrder {
        key2, _ := reference[key1]
        v1, _ := m1[key1]
        v2, _ := m2[key2]
        fmt.Printf("%s/%s: (%d, %d)n", key1, key2, v1, v2)
    }
}

func testMap() map[string]int {
    return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

func testMap2() map[string]int {
    return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}
 

или вы можете измениться reference , чтобы выглядеть примерно так:

 var reference = [][]string{{"Ali", "Ali_1"}, {"Cat", "Cat1"}, {"Bob", "Bob"}}
 

(Что было бы более гибким, если у вас задействовано более двух карт, но вы должны убедиться, что порядок в подразделах соответствует порядку карт.)

Хотя по мере нашего прогресса это становится все более сложным. Вы могли бы рассмотреть совершенно другой подход, возможно, используя более сложные типы, такие как структуры или что-то в этом роде. Или сделайте шаг назад и подумайте, почему у вас в первую очередь эти несоответствующие ключи.