Home > Software engineering >  How to combine specific elements in an array to create a new array?
How to combine specific elements in an array to create a new array?

Time:03-07

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

CodePudding user response:

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] = []

CodePudding user response:

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)
      }
    )
  }
}

CodePudding user response:

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]) )
}
  • Related