1

Given this array of values:

let values = [
    ["2020-01-01", 1, 3, 2],
    ["2020-02-01", 10, 30, 20],
    ["2020-03-01", 100, 300, 200]
]

How can I convert it in something like this?:

public struct Point {
    var date: String
    var price: Double
}

let expectedResult: [[Point]] = [
    [Point(date: "2020-01-01", price: 1), Point(date: "2020-02-01", price: 10), Point(date: "2020-03-01", price: 100)],
    [Point(date: "2020-01-01", price: 3), Point(date: "2020-02-01", price: 30), Point(date: "2020-03-01", price: 300)],
    [Point(date: "2020-01-01", price: 2), Point(date: "2020-02-01", price: 20), Point(date: "2020-03-01", price: 200)]
]

I expect values to always have 1 String and a different number of Doubles, from that I need an array of Point for each of those Doubles.

I've tried different approaches with .map or nested for loops but I never get to the desired result or I end up with a very hard to read code.

Ludyem
  • 1,709
  • 1
  • 18
  • 33
  • A `String` is not a `Date`. You should use `Date`. And you should also be careful of using `Double` for currency, as it'll give you perhaps unexpected results. https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency – Alexander May 09 '21 at 12:55
  • 1
    Yeah I'm not using either String or Double, I just put them here to keep the example simple, the strings in the example could as well be "A", "B", "C" – Ludyem May 09 '21 at 12:58
  • 1
    Okay good good, just checking. – Alexander May 09 '21 at 13:06

2 Answers2

1

you can do this:

import UIKit

let values = [
    ["2020-01-01", 1.0, 3.0, 2.0],
    ["2020-02-01", 10.0, 30.0, 20.0],
    ["2020-03-01", 100.0, 300.0, 200.0]
]

public struct Point {
    var date: String
    var price: Double
}

var expectedResult: [[Point]] = []

for i in 1..<values[0].count {
    var points: [Point] = []
    for j in 0..<values.count {
        points.append(Point(date: values[j][0] as! String, price: values[j][i] as! Double))
    }
    expectedResult.append(points)
}

print(expectedResult)
Esraa Ragab
  • 296
  • 2
  • 9
0

The input is really quite suspicious ([Any] is never fun to work with, you should try to avoid it.), but all you need is two simple maps.

let values = [
    ["2020-01-01", 1, 3, 2],
    ["2020-02-01", 10, 30, 20],
    ["2020-03-01", 100, 300, 200]
]

public struct Point {
    var date: String
    var price: Double
}

let points: [[Point]] = values.map { pointData in
    let date = pointData.first! as! String // You REALLY should parse this into a `Date`.
    let prices = pointData.dropFirst()
    
    return prices.map { Point(date: date, price: Double($0 as! Int)) }
}

points.forEach { print($0) }
Alexander
  • 59,041
  • 12
  • 98
  • 151
  • This doesn't give the expect result, for example the first array end up being: `[Point(date: "2020-01-01", price: 1), Point(date: "2020-01-01", price: 3), Point(date: "2020-01-01", price: 2)] ` instead of `[Point(date: "2020-01-01", price: 1), Point(date: "2020-02-01", price: 10), Point(date: "2020-03-01", price: 100)]` – Ludyem May 09 '21 at 12:59
  • Sounds like you just need to transpose the result. https://stackoverflow.com/q/39889568/3141234 – Alexander May 09 '21 at 13:08
  • Now this is even more strange, the groupings you have look like this, https://imgur.com/a/7VDJT0b What's the pattern? – Alexander May 09 '21 at 13:13
  • basically each array in `values` contains the points needed to make 3 charts. for example in: `["2020-01-01", 1, 3, 2]` `"2020-01-01"` is the point in the X axis and `1` would be the point in the Y axis for the first chart, `3` and `2` are the Y points for other two charts with the same X axis value. That's why I need this to end up being 3 different arrays to make 3 different charts. It's way more complex then what it needed to be but I don't have a say in the way I get these values so I have to stick with this approach – Ludyem May 09 '21 at 13:34
  • Interesting. Welp, transposing will the do the job. – Alexander May 09 '21 at 14:59