@tim-code/my-util 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tim-code/my-util",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "author": "",
package/src/find.js CHANGED
@@ -182,7 +182,7 @@ export function findClosest(array, value, options = {}) {
182
182
  case "abs":
183
183
  return findClosestAbs(array, value, options)
184
184
  default:
185
- throw new Error(`Unknown comparator: ${comparator}`)
185
+ throw new Error(`unknown comparator: ${comparator}`)
186
186
  }
187
187
  }
188
188
 
package/src/find.test.js CHANGED
@@ -207,7 +207,7 @@ describe("findClosest", () => {
207
207
 
208
208
  it("throws on unknown comparator", () => {
209
209
  expect(() => findClosest([1, 5, 9], 6, { comparator: "foo" })).toThrow(
210
- "Unknown comparator: foo"
210
+ "unknown comparator: foo"
211
211
  )
212
212
  })
213
213
 
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from "./array.js"
2
- export { findClosest } from "./find.js"
2
+ export * from "./find.js"
3
3
  export * from "./math.js"
4
4
  export * from "./object.js"
5
5
  export * from "./promise.js"
package/src/math.js CHANGED
@@ -23,6 +23,85 @@ export function line([x1, y1], [x2, y2]) {
23
23
  return (x) => m * x + b
24
24
  }
25
25
 
26
+ /**
27
+ * Calculate the sum of values in an array.
28
+ * @template T
29
+ * @param {Array<T>} array
30
+ * @param {Object} [options]
31
+ * @param {string|number|((element: T, index: number, array: Array<T>) => number)=} options.key
32
+ * @returns {number}
33
+ */
34
+ export function sum(array, { key } = {}) {
35
+ let total = 0
36
+ if (typeof key === "function") {
37
+ for (let i = 0; i < array.length; i++) {
38
+ total += key(array[i], i, array)
39
+ }
40
+ } else if (typeof key === "string" || typeof key === "number") {
41
+ for (let i = 0; i < array.length; i++) {
42
+ total += array[i][key]
43
+ }
44
+ } else {
45
+ for (let i = 0; i < array.length; i++) {
46
+ total += array[i]
47
+ }
48
+ }
49
+ return total
50
+ }
51
+
52
+ /**
53
+ * Calculate the average (mean) of values in an array.
54
+ * @template T
55
+ * @param {Array<T>} array
56
+ * @param {Object} [options]
57
+ * @param {string|number|((element: T, index: number, array: Array<T>) => number)=} options.key
58
+ * @returns {number}
59
+ * @throws {Error} If the array is empty.
60
+ */
61
+ export function average(array, { key } = {}) {
62
+ if (array.length === 0) {
63
+ throw new Error("cannot compute average of empty array")
64
+ }
65
+ return sum(array, { key }) / array.length
66
+ }
67
+
68
+ /**
69
+ * Calculate the variance of values in an array.
70
+ * @template T
71
+ * @param {Array<T>} array
72
+ * @param {Object} [options]
73
+ * @param {string|number|((element: T, index: number, array: Array<T>) => number)=} options.key
74
+ * @returns {number}
75
+ * @throws {Error} If the array is empty.
76
+ */
77
+ export function variance(array, { key } = {}) {
78
+ if (array.length === 0) {
79
+ throw new Error("cannot compute variance of empty array")
80
+ }
81
+ const avg = average(array, { key })
82
+ let total = 0
83
+ if (typeof key === "function") {
84
+ for (let i = 0; i < array.length; i++) {
85
+ const value = key(array[i], i, array)
86
+ const diff = value - avg
87
+ total += diff * diff
88
+ }
89
+ } else if (typeof key === "string" || typeof key === "number") {
90
+ for (let i = 0; i < array.length; i++) {
91
+ const value = array[i][key]
92
+ const diff = value - avg
93
+ total += diff * diff
94
+ }
95
+ } else {
96
+ for (let i = 0; i < array.length; i++) {
97
+ const value = array[i]
98
+ const diff = value - avg
99
+ total += diff * diff
100
+ }
101
+ }
102
+ return total / array.length
103
+ }
104
+
26
105
  /**
27
106
  * Prepend a plus to a number or string if positive.
28
107
  * @param {number|string} number Or string
package/src/math.test.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "@jest/globals"
2
- const { mod, formatPlus, line } = await import("./math.js")
2
+ const { mod, formatPlus, line, sum, average, variance } = await import("./math.js")
3
3
 
4
4
  describe("mod", () => {
5
5
  it("returns n when n is less than m and n is non-negative", () => {
@@ -104,6 +104,102 @@ describe("line", () => {
104
104
  })
105
105
  })
106
106
 
107
+ describe("sum", () => {
108
+ it("returns 0 for an empty array", () => {
109
+ expect(sum([])).toBe(0)
110
+ })
111
+
112
+ it("sums a simple array of numbers", () => {
113
+ expect(sum([1, 2, 3])).toBe(6)
114
+ expect(sum([-1, 1, 2])).toBe(2)
115
+ })
116
+
117
+ it("sums using a key function", () => {
118
+ const arr = [{ v: 2 }, { v: 3 }, { v: 4 }]
119
+ expect(sum(arr, { key: (el) => el.v })).toBe(9)
120
+ expect(sum(arr, { key: (el, i) => el.v * i })).toBe(0 * 2 + 1 * 3 + 2 * 4) // 0 + 3 + 8 = 11
121
+ })
122
+
123
+ it("sums using a string key", () => {
124
+ const arr = [{ v: 2 }, { v: 3 }, { v: 4 }]
125
+ expect(sum(arr, { key: "v" })).toBe(9)
126
+ })
127
+
128
+ it("sums using a numeric key", () => {
129
+ const arr = [[1], [2], [3]]
130
+ expect(sum(arr, { key: 0 })).toBe(6)
131
+ })
132
+
133
+ it("handles array of numbers with undefined options", () => {
134
+ expect(sum([5, 6, 7])).toBe(18)
135
+ expect(sum([5, 6, 7], undefined)).toBe(18)
136
+ })
137
+
138
+ it("returns NaN if key is string/number and property is missing", () => {
139
+ expect(sum([{ a: 1 }, {}], { key: "a" })).toBeNaN()
140
+ })
141
+ })
142
+
143
+ describe("average", () => {
144
+ it("computes the mean of a number array", () => {
145
+ expect(average([1, 2, 3])).toBe(2)
146
+ expect(average([1, 1, 1, 1])).toBe(1)
147
+ })
148
+
149
+ it("computes the mean using a key function", () => {
150
+ const arr = [{ v: 2 }, { v: 4 }]
151
+ expect(average(arr, { key: (el) => el.v })).toBe(3)
152
+ })
153
+
154
+ it("computes the mean using a string key", () => {
155
+ const arr = [{ v: 2 }, { v: 4 }]
156
+ expect(average(arr, { key: "v" })).toBe(3)
157
+ })
158
+
159
+ it("computes the mean using a numeric key", () => {
160
+ const arr = [[2], [4]]
161
+ expect(average(arr, { key: 0 })).toBe(3)
162
+ })
163
+
164
+ it("throws for empty array", () => {
165
+ expect(() => average([])).toThrow("cannot compute average of empty array")
166
+ })
167
+
168
+ it("returns NaN if key is string/number and property is missing", () => {
169
+ expect(average([{ a: 1 }, {}], { key: "a" })).toBeNaN()
170
+ })
171
+ })
172
+
173
+ describe("variance", () => {
174
+ it("computes the variance of a number array", () => {
175
+ expect(variance([1, 2, 3])).toBeCloseTo(2 / 3)
176
+ expect(variance([1, 1, 1, 1])).toBe(0)
177
+ })
178
+
179
+ it("computes the variance using a key function", () => {
180
+ const arr = [{ v: 2 }, { v: 4 }]
181
+ expect(variance(arr, { key: (el) => el.v })).toBe(1)
182
+ })
183
+
184
+ it("computes the variance using a string key", () => {
185
+ const arr = [{ v: 2 }, { v: 4 }]
186
+ expect(variance(arr, { key: "v" })).toBe(1)
187
+ })
188
+
189
+ it("computes the variance using a numeric key", () => {
190
+ const arr = [[2], [4]]
191
+ expect(variance(arr, { key: 0 })).toBe(1)
192
+ })
193
+
194
+ it("throws for empty array", () => {
195
+ expect(() => variance([])).toThrow("cannot compute variance of empty array")
196
+ })
197
+
198
+ it("returns NaN if key is string/number and property is missing", () => {
199
+ expect(variance([{ a: 1 }, {}], { key: "a" })).toBeNaN()
200
+ })
201
+ })
202
+
107
203
  describe("formatPlus", () => {
108
204
  it("prepends a plus for positive numbers", () => {
109
205
  expect(formatPlus(1)).toBe("+1")