Многомерный массив Swift 3, работал в Swift 2.2 и предыдущих версиях

#arrays #swift #multidimensional-array #swift3 #xcode8

#массивы #swift #многомерный массив #swift3 #xcode8

Вопрос:

Я часами ломал голову и чувствую, что перепробовал большинство вещей, поэтому я обращаюсь к надежному Stack Overflow!

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

[[1475511843000,183649999],[1475512143000,183612691],[1475512443000,183503638]]

Раньше я просто устанавливал эту переменную как var graphPoints:NSArray = []

Сейчас я пытаюсь преобразовать в Swift3 и использовать [[UInt32:Int]]() , чтобы указать, что у меня есть массив, содержащий другие массивы, которые имеют 32 целых числа без знака, а также целое число впоследствии. Независимо от того, какой способ я пробовал, включая стандартный или подслащенный синтаксис:

[Int:[UInt32:Int]]()

[[UInt32:Int]]()

[[]]()

позволяет мне получить доступ ко второму массиву из-за проблемы с вводом, обычно выдает ошибку, похожую на Type 'Int?' has no subscript members .

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

Вызов сервера выглядит следующим образом: `Alamofire.request(urlString).responseJSON { ответ в ответе коммутатора.результат { case .success(пусть данные): пусть json = JSON(данные);

             //print("GRAPH DATA POINTS JSON: (json)")

            //some graphs don't contain data so we have to test for null
            if !json.isEmpty {
                self.graphPoints = json["data"].arrayObject! as! [(timestamp: UInt64, value: Int)]
                if self.graphPoints.count > 0 {
                    self.firstPriceInGraph = self.graphPoints[0][0].doubleValue
                    self.setupPercentageLabel()
                } else {
                    //no graph data available, hide something?
                    self.firstPriceInGraph = -1.0
                    if Helper.__DEBUG { print("NO DATA IN JSON... 1")}
                }
            } else {
                //no graph data available, hide something?
                self.firstPriceInGraph = -1.0
                if Helper.__DEBUG {print("NO DATA IN JSON... 2")}
            }

            self.graphView.reloadData()

        case .failure(let error):
            self.graphPoints = [(timestamp:UInt64, value:Int)]()
            self.graphView.reloadData()
            print("Get Graph Data - Request failed with error: (error)")
        }
    }`
  

Ошибка

When trying Andrey Gordeev's answer
Начальная настройка массива

введите описание изображения здесь

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

1. У вас есть массив массива, и в первых двух объявлениях вы указываете, что это массив словаря, попробуйте один раз [[UInt32]]

2. @NiravD 1475511843000 не подходит UInt32 . UInt64 здесь лучший выбор.

3. Похоже, OP просто хочет, чтобы старый код Swift 2.2 отлично работал с Swift 3.0 🙂 К сожалению, иногда это невозможно.

4. @StuartP. это имеет смысл. Смотрите мой обновленный ответ.

5. На самом деле, я не думаю, что это помогает. Существует проблема с graphPoints и firstPriceInGraph : у них неправильные типы

Ответ №1:

Как вы и сказали, это Array из других Array s. [[UInt32:Int]]() вместо этого создал бы Array Dictionary значение s, потому [UInt32:Int] что это a Dictionary с UInt32 ключами as и Int значениями as.

Массивы Swift содержат только один тип элемента, поэтому вы можете сделать [[Integer]] , Integer будучи протоколом, которому UInt32 Int соответствуют оба и. Затем при доступе вам пришлось бы явно приводить к либо UInt32 или Int , если вы хотите, чтобы они были в этих типах.

Вы также можете затем преобразовать это [[Integer]] в a [(UInt32, Int)] , an Array из кортежей, содержащих a UInt32 и an Int .

Ответ №2:

Сейчас я пытаюсь преобразовать в Swift 3 и использовать [[UInt32:Int]]() , чтобы указать, что у меня есть массив, содержащий другие массивы, которые имеют 32 целых числа без знака, а также целое число после этого.

Это совсем не то, что это значит. [[UInt32: Int]]() является сокращением для: Array<Dictionary<UInt32, Int>>.init()

Единственный способ получить массив из 2 типов, таких как UInt32 и Int , — это сохранить в массиве супертип обоих этих типов. В этом случае, UInt32 и Int оба имеют общее соответствие Integer протоколу, поэтому вы можете хранить оба UInt32 и Int в Array<Integer> . Однако это довольно грубо, поскольку для этого вам потребуется постоянно явно выполнять приведение из Integer в UInt32 или Int . Косвенность, которую это вводит, также приводит к снижению производительности.

Лучший способ добиться аналогичного результата — хранить кортежи UInt32 и Int:

 let graphPoints: [(UInt32, Int)] = [
    (1475511843000, 183649999),
    (1475512143000, 183612691),
    (1475512443000, 183503638)
]
  

Однако это даже не работает, потому 1475511843000 что слишком велико для остановки в a UInt32 , максимальное значение которого равно 4294967295 ( UInt32.max ) .

Ответ №3:

То, что вы написали, является словарем, а не многомерным массивом.

 [[UInt32:Int]]()
  

создает массив словарей, который имеет UInt32 как ключи, Int так и значения.

 [Int:[UInt32:Int]]()
  

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

Оба вышеперечисленных не то, что вы хотите.

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

Мое предложение — использовать массив кортежей:

 [(UInt32, Int)]
  

Пример использования:

 theArray[3].0 // get the timestamp of the fourth item
theArray[7].1 // get the Int value of the eighth item
  

В качестве альтернативы попробуйте использовать словарь:

 [UInt32: Int]
  

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

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

1. Похоже, это приводит к тому Cannot subscript a value of type 'inout [(timestamp: UInt64, value: Int)]' (aka 'inout Array<(timestamp: UInt64, value: Int)>') , что при попытке получить доступ к данным следующим образом let timestamp = self.graphPoints[0].timestamp

2. @StuartP. Кажется, я не могу воспроизвести это. Можете ли вы отредактировать свой вопрос, чтобы показать больше кода?

Ответ №4:

Как насчет этого:

 let array = [[UInt64]]() 
  

или

 let array: [[UInt64]] = [[1475511843000,183649999],[1475512143000,183612691],[1475512443000,183503638]]
  

То, что вы пытаетесь определить с помощью [Int:[UInt32:Int]]() and [[UInt32:Int]]() , не является массивом массивов. Первый — это словарь, где значение — это другой словарь. Второй — это массив словарей.

PS: Как упоминал Александр Момчилов, лучше обернуть ваши данные в [(UInt64, Int)]

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

1. Type 'UInt64' has no subscript members это результат, но я попытаюсь обернуть данные, каков наилучший способ извлечь данные из этого, поскольку я полагаю, что это не будет, например, через [0] [0] . Также я считаю, что типы данных должны быть частью этого сейчас, так что, возможно [(timestamp:UInt64, value:Int)]

2. Type 'UInt64' has no subscript members является результатом чего?

3. let array = [[UInt64]]() Когда я пытаюсь получить к нему доступ через let value = self.graphPoints[0][0]

4. @StuartP. Что это за тип self.graphPoints ? Вы заменили NSArray на [[UInt64]] ? let value = array[0][0] для меня работает просто отлично. ВОЗВРАТ 1475511843000