0

I have these 3 arrays

names = ["tomatoes", "bananas", "carrot", "tshirt", "microwave"]
categories = ["food", "food", "food", "clothing", "kitchen"]
prices = ["1.49", "0.79", "1.99", "7.99", "200.99"]

I want to create and array like this for each of them

["food", "tomatoes", "1.49"]

I have lots of data so i am trying to create a function that will do this more efficiently then I will try to combine everything into one big array. Ex: [["food", "tomatoes", "1.49"], ["food", "bananas", "0.79"], ["food", "carrot", "1.99"], ["clothing", "tshirt", "7.99"], ["kitchen", "microwave", "200.99"]] I tried using map but I'm not that familiar with programming so I cant wrap my head around this

  • Why do you need to convert from three arrays to an array of three? Btw tuples, or even better, structs, would be a much better candidate for the result. – Cristik Mar 07 '22 at 09:45
  • Also, what should happen if the arrays don't have the same size? – Cristik Mar 07 '22 at 09:46

3 Answers3

3

Not a direct answer to your question but what you really need is to structure your data:

struct Product {
    let name: String
    let category: Category
    let price: Double
}

enum Category: String {
    case food, clothing, kitchen
}

Then you can simply create a product array:

var products: [Product] = []
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
0

You want to zip three sequences, but the standard library only supports two, for now. See this other answer for a great solution that relies on code generation. Here is another solution that does not:

Array([categories, names, prices].zipped)
import Algorithms // for `compacted`

public extension Sequence where Element: Sequence {
  /// Like `zip`, but with no limit to how many sequences are zipped.
  var zipped: AnySequence<[Element.Element]> {
    .init(
      sequence(
        state: map { $0.makeIterator() }
      ) { iterators in
        let compacted = iterators.indices.map { iterators[$0].next() }.compacted()

        guard compacted.count == iterators.count else {
          return nil
        }

        return .init(compacted)
      }
    )
  }
}
-1

The simple way of doing it is to loop over the three arrays in parallel. To prevent index errors you should work to the bounds of the smallest array. You could do it with a for loop, but IMO it's cleaner to use 'reduce(into:)

let items = min(names.count, categories.count, prices.count)
let all = ( 0 ..< items ).reduce(into: [[String]]()) {
   $0.append( [names[$1], categories[$1], prices[$1] ])
}

or, picking up on @Leo Dabus's good advice:

let products = ( 0 ..< items ).reduce(into: [Product]()) {
   $0.append( Product(name: names[$1], category: categories[$1], price: prices[$1]) )
}
flanker
  • 3,840
  • 1
  • 12
  • 20