Skip to content

Commit 80f7daf

Browse files
committed
Semver major algo change, sort now more stable
The way the levenshtein algo works is relative to string size, which in the previous sort implementation could lead to unexpected results. Now we normalize the length of all inputs so the scoring is consistent across the data set, resulting in less unexpected sorting results.
1 parent aa1256b commit 80f7daf

File tree

3 files changed

+65
-41
lines changed

3 files changed

+65
-41
lines changed

index.js

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,72 @@
11
'use strict'
22

33
var levenSrc = require('leven')
4+
var bufChar = String.fromCharCode(2000)
45

5-
var maxDist = function (a, b, c) {
6-
var aLen = (a || '').length
7-
var bLen = (b || '').length
6+
module.exports = function (ary, src1, key1, src2, key2) {
7+
var max = 0
8+
ary.forEach(function (el) {
9+
if (!el) return
10+
if (!key1 && !key2 && el.length > max) max = el.length
811

9-
return (aLen > bLen ? aLen : bLen) || 1
10-
}
12+
if (key1 instanceof Array) {
13+
return key1.forEach(function (k) {
14+
if (k && el[k] && el[k].length > max) max = el[k].length
15+
})
16+
}
1117

12-
var leven = function (a, b) {
13-
if (a === b) return 0
14-
if (!a || !b) return maxDist(a, b)
18+
if (key1 && el[key1] && el[key1].length > max) max = el[key1].length
19+
if (key2 && el[key2] && el[key2].length > max) max = el[key2].length
20+
})
1521

16-
return levenSrc(a, b)
17-
}
22+
var maximize = function (val) {
23+
if (!val || val.length === max) return val
24+
return val + Array(max - val.length).join(bufChar)
25+
}
1826

19-
var levSort = function (src, a, b) {
20-
if (!a) return 1
21-
if (!b) return -1
27+
var maxDist = function (a, b, c) {
28+
var aLen = (a || '').length
29+
var bLen = (b || '').length
2230

23-
a = leven(src, a)
24-
b = leven(src, b)
31+
return (aLen > bLen ? aLen : bLen) || 1
32+
}
2533

26-
return a - b
27-
}
34+
var leven = function (a, b) {
35+
if (a === b) return 0
2836

29-
var levMinInAry = function (array, src) {
30-
var min = 1000
31-
var len = array.length
37+
b = maximize(b)
3238

33-
for (var counter = 0; counter < len; counter++) {
34-
var val = array[counter]
39+
if (!a || !b) return maxDist(a, b)
3540

36-
if (val && val.length && val.length > 0) {
37-
var levScore = leven(src, array[counter])
38-
if (levScore < min) min = levScore
39-
}
41+
return levenSrc(a, b)
4042
}
4143

42-
return min
43-
}
44+
var levSort = function (src, a, b) {
45+
if (!a) return 1
46+
if (!b) return -1
47+
48+
a = leven(src, a)
49+
b = leven(src, b)
50+
51+
return a - b
52+
}
53+
54+
var levMinInAry = function (array, src) {
55+
var min = 1000
56+
var len = array.length
57+
58+
for (var counter = 0; counter < len; counter++) {
59+
var val = array[counter]
60+
61+
if (val && val.length && val.length > 0) {
62+
var levScore = leven(src, array[counter])
63+
if (levScore < min) min = levScore
64+
}
65+
}
66+
67+
return min
68+
}
4469

45-
module.exports = function (ary, src1, key1, src2, key2) {
4670
var sorted = ary.sort(function (a, b) {
4771
if (key1 instanceof Array) {
4872
var aLev = levMinInAry(key1.map(function (k) { return a[k] }), src1)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "leven-sort",
3-
"version": "2.0.0",
3+
"version": "3.0.0",
44
"main": "index.js",
55
"files": [
66
"index.js"

test.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@ runTests('Testing leven-sort', () => {
2525
'Bill Griffin',
2626
'Billy Griffith',
2727
'Billy Campbell',
28-
'Alan King',
2928
'William George',
3029
'Carl Martinez',
3130
'Roger Davis',
3231
'Benjamin Wilson',
3332
'Dennis Smith',
3433
'Andrew Torres',
34+
'Alan King',
3535
null
3636
]
3737

3838
const levSorted = levenSort(nameAry, sourceName)
3939

40-
return test('samesies', JSON.stringify(levSorted), JSON.stringify(expect))
40+
return test('Simple same', JSON.stringify(levSorted), JSON.stringify(expect))
4141
})
4242

4343
test(`sorts array of objects, with secondary sort`, () => {
@@ -62,19 +62,19 @@ runTests('Testing leven-sort', () => {
6262
{ first: 'Bill', last: 'Griffin' },
6363
{ first: 'Billy', last: 'Griffith' },
6464
{ first: 'Billy', last: 'Campbell' },
65+
{ first: 'William', last: 'George' },
66+
{ first: 'Dennis', last: 'Smith' },
6567
{ first: 'Carl', last: 'Martinez' },
68+
{ first: 'Benjamin', last: 'Wilson' },
6669
{ first: 'Alan', last: 'King' },
67-
{ first: 'William', last: 'George' },
6870
{ first: 'Roger', last: 'Davis' },
69-
{ first: 'Dennis', last: 'Smith' },
7071
{ first: 'Andrew', last: 'Torres' },
71-
{ first: 'Benjamin', last: 'Wilson' },
7272
{ first: null, last: null }
7373
]
7474

7575
const levSorted = levenSort(nameObjAry, sourceFirst, 'first', sourceLast, 'last')
7676

77-
return test('samesies', JSON.stringify(levSorted), JSON.stringify(expect))
77+
return test('Secondary same', JSON.stringify(levSorted), JSON.stringify(expect))
7878
})
7979

8080
test(`sorts array of objects by multiple keys`, () => {
@@ -98,18 +98,18 @@ runTests('Testing leven-sort', () => {
9898
{ first: 'Bill', last: 'Griffin' },
9999
{ first: 'Billy', last: 'Griffith' },
100100
{ first: 'Billy', last: 'Campbell' },
101-
{ first: 'Carl', last: 'Martinez' },
102-
{ first: 'Alan', last: 'King' },
103-
{ first: 'Benjamin', last: 'Wilson' },
104101
{ first: 'William', last: 'George' },
105-
{ first: 'Dennis', last: 'Smith' },
102+
{ first: 'Benjamin', last: 'Wilson' },
106103
{ first: 'Roger', last: 'Davis' },
104+
{ first: 'Dennis', last: 'Smith' },
105+
{ first: 'Carl', last: 'Martinez' },
106+
{ first: 'Alan', last: 'King' },
107107
{ first: 'Andrew', last: 'Torres' },
108108
{ first: null, last: null }
109109
]
110110

111111
const levSorted = levenSort(nameObjAry, source, ['first', 'last'])
112112

113-
return test('samesies', JSON.stringify(levSorted), JSON.stringify(expect))
113+
return test('Key array same', JSON.stringify(levSorted), JSON.stringify(expect))
114114
})
115115
})

0 commit comments

Comments
 (0)