1 | 'use strict'
|
2 |
|
3 | const flatten = require('../../utils/array').flatten
|
4 | const containsCollections = require('../../utils/collection/containsCollections')
|
5 |
|
6 | function factory (type, config, load, typed) {
|
7 | const add = load(require('../arithmetic/addScalar'))
|
8 | const divide = load(require('../arithmetic/divideScalar'))
|
9 | const compare = load(require('../relational/compare'))
|
10 | const partitionSelect = load(require('../matrix/partitionSelect'))
|
11 | const improveErrorMessage = load(require('./utils/improveErrorMessage'))
|
12 |
|
13 | |
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 | const median = typed('median', {
|
40 |
|
41 | 'Array | Matrix': _median,
|
42 |
|
43 |
|
44 | 'Array | Matrix, number | BigNumber': function (array, dim) {
|
45 |
|
46 | throw new Error('median(A, dim) is not yet supported')
|
47 |
|
48 | },
|
49 |
|
50 |
|
51 | '...': function (args) {
|
52 | if (containsCollections(args)) {
|
53 | throw new TypeError('Scalar values expected in function median')
|
54 | }
|
55 |
|
56 | return _median(args)
|
57 | }
|
58 | })
|
59 |
|
60 | |
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 | function _median (array) {
|
67 | try {
|
68 | array = flatten(array.valueOf())
|
69 |
|
70 | const num = array.length
|
71 | if (num === 0) {
|
72 | throw new Error('Cannot calculate median of an empty array')
|
73 | }
|
74 |
|
75 | if (num % 2 === 0) {
|
76 |
|
77 | const mid = num / 2 - 1
|
78 | const right = partitionSelect(array, mid + 1)
|
79 |
|
80 |
|
81 | let left = array[mid]
|
82 | for (let i = 0; i < mid; ++i) {
|
83 | if (compare(array[i], left) > 0) {
|
84 | left = array[i]
|
85 | }
|
86 | }
|
87 |
|
88 | return middle2(left, right)
|
89 | } else {
|
90 |
|
91 | const m = partitionSelect(array, (num - 1) / 2)
|
92 |
|
93 | return middle(m)
|
94 | }
|
95 | } catch (err) {
|
96 | throw improveErrorMessage(err, 'median')
|
97 | }
|
98 | }
|
99 |
|
100 |
|
101 | const middle = typed({
|
102 | 'number | BigNumber | Complex | Unit': function (value) {
|
103 | return value
|
104 | }
|
105 | })
|
106 |
|
107 |
|
108 | const middle2 = typed({
|
109 | 'number | BigNumber | Complex | Unit, number | BigNumber | Complex | Unit': function (left, right) {
|
110 | return divide(add(left, right), 2)
|
111 | }
|
112 | })
|
113 |
|
114 | median.toTex = undefined
|
115 |
|
116 | return median
|
117 | }
|
118 |
|
119 | exports.name = 'median'
|
120 | exports.factory = factory
|