Evgeniy Kleban
Evgeniy Kleban

Reputation: 6965

Division of array of doubles

I have array of Doubles:

var dates: [Double] = [1542412800000,
    1542499200000,
    1543017600000,
    1543708800000,
    1544659200000,
    1547164800000,
    1550880000000]

(yes, it's actually date timestamps). What I want is to transform it to an array of percentages. For example, if I had an array of [5, 20, 25], I want an output of [0.20, 0.8, 1], percentages of current values. I ended up with:

let percentages: [Double] = dates
    .map{$0 - dates.first!}
    .map{$0/dates.last!}
percentages.forEach{ it in
    print(it)
}

But output is:

0.0
5.5710306406685235e-05
0.00038997214484679665
0.0008356545961002785
0.0014484679665738162
0.003064066852367688
0.005459610027855153

Second value kind of weird. How to solve this?

Upvotes: 0

Views: 38

Answers (3)

Vyacheslav
Vyacheslav

Reputation: 27221

Using your code style you should use something like this:

var dates: [Double] = [1542412800000,
                       1542499200000,
                       1543017600000,
                       1543708800000,
                       1544659200000,
                       1547164800000,
                       1550880000000]

let intermediate: [Double] = dates
    .map{$0 - dates.first!}
    let percentages = intermediate
    .map{$0/intermediate.last!}
percentages.forEach{ it in
    print(it)
}

The real problem that you divide each element by 'initial' maximum value (not shifted by minimum value).

Upvotes: 1

ielyamani
ielyamani

Reputation: 18591

You can do it this way :

let dates: [Double] = [1542412800000,
                       1542499200000,
                       1543017600000,
                       1543708800000,
                       1544659200000,
                       1547164800000,
                       1550880000000]

let sorted = dates.sorted()

guard let first = sorted.first,
    let last = sorted.last,
    last != first
    else {
    fatalError()
}

let denominator = last - first

let percentages = sorted.map { ($0 - first)/denominator }

print(percentages) //[0.0, 0.01020408163265306, 0.07142857142857142, 0.15306122448979592, 0.2653061224489796, 0.5612244897959183, 1.0]

Upvotes: 2

Palle
Palle

Reputation: 12129

When dividing every value by the last value in the last map statement, you are ignoring the fact, that everything has already been subtracted by the first value.

To fix this, you should divide by the range of values (the difference between the maximum value and the minimum value).

Assuming your array is sorted, this will be:

guard let maxValue = dates.last, let minValue = dates.first else {
    return
}
let percentages = dates
    .map {$0 - minValue}
    .map {$0 / (maxValue - minValue)}

This will normalize all values such that the first value is 0 and the last value is 1 and everything else is in between.

If you do not want to normalize the first value to 0 (but keep everything between 0 and 1), you can omit the subtraction step:

let percentages = dates.map {$0 / maxValue}

If your array is not sorted, you can use the .min() and .max() functions of your array:

guard let maxValue = dates.max(), let minValue = dates.min() else {
    return
}

Upvotes: 2

Related Questions