Как я могу отсортировать массив фиксированной длины в Голанге? - PullRequest
0 голосов
/ 22 сентября 2018

У меня есть следующий многомерный массив:

x := [2][3]int{
    {3, 2, 1},
    {3, 2, 1},
}

И строки, и столбцы имеют фиксированный размер.

Я пытаюсь проверить, отсортированы ли строки, и предпринимаюФункция сортировки требует массивов без известного размера.Как я могу попросить пойти обработать предмет с фиксированным, известным размером, как если бы он имел неизвестный размер?

var allTrue bool = true
for i := range x {
  t := sort.Ints(x[i]) == []int{1, 2, 3}
  allTrue = allTrue && t
}

Я получаю:

./main.go:xx:yy: sort.Ints(x[i]) used as value
./main.go:xx:yy: cannot use x[i] (type [3]int) as type []int in argument to sort.Ints

Я читаю этосообщение об ошибке правильно?

Ответы [ 3 ]

0 голосов
/ 22 сентября 2018

Несмотря на этот другой ответ , в котором содержатся рекомендации относительно правильного нарезки для использования пакета sort, я добавил этот ответ, чтобы дать более подробное описание некоторых дальнейших проблем с кодом, который вы опубликовали,Я надеюсь, что это поможет вам понять язык Go.


Введение в ломтики

Я беру на себя обязательство, что функция сортировки требует массивов без известного размера [sic]

Как другие сказали , это не терминология для описания этой концепции в Go.Все массивы Go имеют фиксированный размер, как определено языковой спецификацией .Как вы знаете, массивы имеют тип [N]T для массива, который содержит некоторое неотрицательное число N элементов типа T.Это исправлено во время компиляции и никогда не изменяется во время выполнения вашей программы.

«Массивы без известного размера» наиболее близко соответствуют слайсам .Срезы - это различные типы в Go, которые позволяют представлять последовательности данных определенного типа, где их длина динамически управляется средой выполнения Go.Они относятся к типу []T для элементов типа T.В частности, их размер не является частью определения типа и может изменяться во время выполнения.Для некоторой переменной среза x []T реализация обеспечивает:

  • внутренний резервный массив аналогичного элементарного типа, где реализация управляет выделением памяти и расширением массива при увеличении длины среза
  • его длина len(x) - обозначает количество элементов, которые в настоящее время содержит срез
  • его емкость cap(x) - общая длина среза плюс дополнительный размер подложкимассив, который может выходить за пределы длины из-за операций среза, ограничивающих представление массива или большего массива, выделяемого средой выполнения, чтобы можно было добавлять в элемент больше элементов.

См. Tour of Go и языковая спецификация на ломтиках для получения более подробной информации.


Решение проблемы с кодом

Как отмечено выше, срезы различного типа для массивов , поэтому вы не можете использовать что-то типа [N]T для некоторых N и T, где некоторыетребуется вещь типа []T.

sort.Ints сортирует срез целых чисел на месте - он имеет сигнатуру типа func Ints(a []int).Ваш вызов sort.Ints(x[i]) индексирует массив x по индексу i, который возвращает массив типа [3]int.Это несовместимо с функцией сортировки и приводит к ошибке времени компиляции, которую вы наблюдаете.

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

Выражения срезов задаются в виде a[low : high], где low и high - необязательные целые числа, предоставляющие индексы в основумассив или фрагмент, которые определяют диапазон, который нужно вернуть в новом фрагменте.Ссылка на спецификацию языка выше содержит больше деталей, которые я рекомендую вам прочитать;Достаточно сказать, что самое простое выражение среза a[:] для некоторого массива или среза a является синтаксическим сахаром, означающим a[0:len(a)-1], то есть преобразует массив / срез в срез той же длины.получить срез типа []int из вашего многомерного массива, нарезав: x[i][:]:

  • x[i] возвращает массив типа [3]int, как и раньше
  • разрезание возвращенного массива возвращает срез типа []int, который совместим с sort.Ints.

sort.Ints не возвращает значение, и срезы не сравнимы

Даже если вы исправите эти проблемы с помощью своего кода, остаются следующие проблемы со следующей строкой:

t := sort.Ints(x[i]) == []int{1, 2, 3}
  1. sort.Ints сортирует на месте ;он не возвращает значение, поэтому проверка на равенство не имеет смысла.
  2. sort.Ints работает на срезах, которые не сравнимы.Невозможно вызвать A == B, где A или B является срезом, если только A или B не является специальным идентификатором nil.Это тонкий момент, который описан в спецификации языка .(Помимо: прочитайте эту страницу, так как вы заметите, что массивы сопоставимы.)

Поскольку вы не можете сравнивать фрагменты напрямую, используя оператор равенства ==, проверяя поэлементное равенствоиз срезов требуется:

  • Срезы должны быть одинаковой длины (разная длина означает, что один срез имеет больше элементов, чем другой)
  • Элементы в каждом индексе одного среза идентичны другимломтики.

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

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

package main

import (
    "fmt"
)

func CheckEquality(a, b []int) bool {
    // Slices of dissimilar length are not equal
    if len(a) != len(b) {
        return false
    }

    for i, el := range a {
        if b[i] != el {
            return false
        }
    }

    return true
}

func main() {
    var mySlice = []int{1, 2, 3, 4, 5}
    var mySlice2 = []int{1, 2, 3, 4, 5}   // same as mySlice
    var otherSlice = []int{5, 6, 7, 8, 9} // dissimilar slice
    var longSlice = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}

    fmt.Println(CheckEquality(mySlice, mySlice2))   // Expect true
    fmt.Println(CheckEquality(mySlice, otherSlice)) // Expect false
    fmt.Println(CheckEquality(mySlice, longSlice))  // Expect false
}
0 голосов
/ 24 сентября 2018

Вы можете получить срез из массива с помощью оператора [:], например:

arr := [3]int{1, 2, 3}
slc := arr[:] // []int{1, 2, 3}, backed by arr

Таким образом, вы можете использовать функцию sort.Ints(...):

sort.Ints(x[0][:])
sort.Ints(x[1][:])
// Now both elements of "x" are sorted.
0 голосов
/ 22 сентября 2018

Вы должны нарезать массив с помощью оператора [:], прежде чем использовать его с пакетом sort.См .: Тур по Го: Ломтики и пакет «сортировки» godoc .

Кроме того, вы можете проверить, сортируется ли срез более эффективно, чем сортировать его, используя sort.IntsAreSorted([]int), например так.

var allTrue bool = true
for i := range x {
    if !sort.IntsAreSorted(x[i][:]) {
        allTrue = false
        break
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...