1

I have an array of ages.

I want to split the array in to 4 subarrays by the age value.

A -> 0...25

B -> 26...50

c -> 51...75

d -> 76 +

I have no problem iterating through the array and append to different arrays by the age value.

            let subArrays: [[Int]] = [[], [], [], []]
            for age in ages {
                switch age {
                case 0...25:
                    subArrays[0].append(age)
                case 26...50:
                    subArrays[1].append(age)
                case 51...75:
                    subArrays[2].append(age)
                default:
                    subArrays[3].append(age)
                }
            }

My questions is: Is there a cleaner way to do this using map, split or any other function.

Thanks

1
  • 1
    Is it safe to assume you meant d -> 76+ instead of d -> 85+? Commented Feb 27, 2017 at 0:47

3 Answers 3

3

This doesn't use map or anything fancy but you can easily eliminate the switch:

var subArrays: [[Int]] = [[], [], [], []]
for age in ages {
    subArrays[min((age - 1) / 25, 3)].append(age)
}

The use of min ensures all values of 76 and greater go into the last slot.

And to test, with all boundary cases, try:

let ages = [ 50, 67, 75, 76, 25, 12, 26, 51, 99, 45, 0, 120, 16 ]

And then:

print(subArrays)

Gives:

[[25, 12, 0, 16], [50, 26, 45], [67, 75, 51], [76, 99, 120]]

Sign up to request clarification or add additional context in comments.

3 Comments

* no floats or negative numbers I assume.
@l'L'l The OP's code shows the results being an array of Int so I assume the array of ages are also Int. And nobody has a negative age. But my answer actually puts values from -23 to -1 in the first result array.
True, although depending on how you look at it some scientists might argue someone (not living) could be 11,000 years old too... but maybe that's way off for this question :)
2

A more generic version that does not depend on any mathematical property of your ranges:

func split<T>(array: [T], ranges: [CountableClosedRange<T>]) -> [[T]] {
    var result = Array(repeating: [T](), count: ranges.count)

    for element in array {
        if let subIndex = ranges.index(where: { $0 ~= element }) {
            result[subIndex].append(element)
        }
    }
    return result
}

let ages = [10, 20, 30, 40, 50, 60]
let subarrays = split(array: ages, ranges: [0...25, 26...50, 51...75, 76...Int.max])

Note that it does not check for overlapping ranges.

1 Comment

You would need to pass in better ranges to handle floating point ages if that were desired. The sample ranges would't catch 25.5, for example, if an array of Float ages were used. I only mention this since the goal of your answer is to handle other types.
0

Based on rmaddy's answer (practically the same) but within one line:

let subs = (0...3).map { sub in ages.filter { sub == min(($0 - 1) / 25, 3) } }

1 Comment

This is kind of slick but it is hard to read and understand and it ends up iterating the ages array 4 times instead of just once.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.