Security News
Input Validation Vulnerabilities Dominate MITRE's 2024 CWE Top 25 List
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
match-sorter
Advanced tools
Simple, expected, and deterministic best-match sorting of an array in JavaScript
The match-sorter npm package is a simple, expected, and deterministic best-match sorting of an array in JavaScript. It's used to filter and sort lists of strings or objects by best match against a given query.
Simple string matching
This feature allows you to sort an array of strings by matching against a single query string. It returns the items that match the query, ordered by best match.
import matchSorter from 'match-sorter';
const fruits = ['apple', 'orange', 'grape', 'banana'];
const sortedFruits = matchSorter(fruits, 'ap');
// sortedFruits will be ['apple', 'grape']
Object array matching
This feature allows you to sort an array of objects by matching against a query string on specified object keys. It returns the objects that match the query, ordered by best match.
import matchSorter from 'match-sorter';
const items = [{name: 'apple'}, {name: 'orange'}, {name: 'grape'}, {name: 'banana'}];
const sortedItems = matchSorter(items, 'ap', {keys: ['name']});
// sortedItems will be [{name: 'apple'}, {name: 'grape'}]
Custom ranking strategies
This feature allows you to customize the ranking strategy used for sorting. You can specify the order of ranking methods to tailor the sorting to your needs.
import matchSorter, {rankings} from 'match-sorter';
const books = ['The Hobbit', 'Game of Thrones', 'Curious George'];
const sortedBooks = matchSorter(books, 'th', {rankings: [rankings.STARTS_WITH, rankings.EQUAL, rankings.CONTAINS]});
// sortedBooks will be ['The Hobbit', 'Game of Thrones']
Fuse.js is a powerful, lightweight fuzzy-search library with a similar goal to match-sorter. It provides flexible searching with customizable search options, but it might be more complex to use for simple use cases compared to match-sorter.
Fuzzy is a JavaScript module for fuzzy string matching. It's useful for filtering large arrays of strings or objects by a search term. It's less feature-rich and has a simpler API than match-sorter, which might be preferable for basic use cases.
Quick-score is a library for scoring and sorting string matches for autocomplete suggestions. It's optimized for speed and is a good alternative to match-sorter when performance is a critical factor.
Simple, expected, and deterministic best-match sorting of an array in JavaScript
This follows a simple and sensible (user friendly) algorithm that makes it easy for you to filter and sort a list of items based on given input. Items are ranked based on sensible criteria that result in a better user experience.
To explain the ranking system, I'll use countries as an example:
France
would match France
, but not france
)France
would match france
)Sou
would match South Korea
or South Africa
)Repub
would match Dominican Republic
)camelCase
, PascalCase
, snake_case
or kebab-case
), then if one of the parts starts with the given value (ex. kingdom
would match unitedKingdom
or united_kingdom
)uk
would match united-kingdom
or UnitedKingdom
)ham
would match Bahamas
)us
would match United States
)iw
would match Zimbabwe
, but not Kuwait
because it must be in the same order). Furthermore, if the item is a closer match, it will rank higher (ex. ua
matches Uruguay
more closely than United States of America
, therefore Uruguay
will be ordered before United States of America
)This ranking seems to make sense in people's minds. At least it does in mine. Feedback welcome!
This module is distributed via npm which is bundled with node and should
be installed as one of your project's dependencies
:
npm install --save match-sorter
const matchSorter = require('match-sorter')
// ES6 imports work too
// Also available in global environment via `matchSorter` global
const list = ['hi', 'hey', 'hello', 'sup', 'yo']
matchSorter(list, 'h') // ['hi', 'hey', 'hello']
matchSorter(list, 'y') // ['yo', 'hey']
matchSorter(list, 'z') // []
[string]
Default: undefined
By default it just uses the value itself as above. Passing an array tells match-sorter which keys to use for the ranking.
const objList = [
{name: 'Janice', color: 'Green'},
{name: 'Fred', color: 'Orange'},
{name: 'George', color: 'Blue'},
{name: 'Jen', color: 'Red'},
]
matchSorter(objList, 'g', {keys: ['name', 'color']})
// [{name: 'George', color: 'Blue'}, {name: 'Janice', color: 'Green'}, {name: 'Fred', color: 'Orange'}]
matchSorter(objList, 're', {keys: ['color', 'name']})
// [{name: 'Jen', color: 'Red'}, {name: 'Janice', color: 'Green'}, {name: 'Fred', color: 'Orange'}, {name: 'George', color: 'Blue'}]
Array of values: When the specified key matches an array of values, the best match from the values of in the array is going to be used for the ranking.
const iceCreamYum = [
{favoriteIceCream: ['mint', 'chocolate']},
{favoriteIceCream: ['candy cane', 'brownie']},
{favoriteIceCream: ['birthday cake', 'rocky road', 'strawberry']},
]
matchSorter(iceCreamYum, 'cc', {keys: ['favoriteIceCream']})
// [{favoriteIceCream: ['candy cane', 'brownie']}, {favoriteIceCream: ['mint', 'chocolate']}]
Nested Keys: You can specify nested keys using dot-notation.
const nestedObjList = [
{name: {first: 'Janice'}},
{name: {first: 'Fred'}},
{name: {first: 'George'}},
{name: {first: 'Jen'}},
]
matchSorter(nestedObjList, 'j', {keys: ['name.first']})
// [{name: {first: 'Janice'}}, {name: {first: 'Jen'}}]
const nestedObjList = [
{name: [{first: 'Janice'}]},
{name: [{first: 'Fred'}]},
{name: [{first: 'George'}]},
{name: [{first: 'Jen'}]},
]
matchSorter(nestedObjList, 'j', {keys: ['name.0.first']})
// [{name: {first: 'Janice'}}, {name: {first: 'Jen'}}]
// matchSorter(nestedObjList, 'j', {keys: ['name[0].first']}) does not work
Property Callbacks: Alternatively, you may also pass in a callback function that resolves the value of the key(s) you wish to match on. This is especially useful when interfacing with libraries such as Immutable.js
const list = [
{name: 'Janice'},
{name: 'Fred'},
{name: 'George'},
{name: 'Jen'},
]
matchSorter(list, 'j', {keys: [(item) => item.name]})
// [{name: 'Janice'}, {name: 'Jen'}]
Min and Max Ranking: You may restrict specific keys to a minimum or maximum ranking by passing in an object. A key with a minimum rank will only get promoted if there is at least a simple match.
const tea = [
{tea: 'Earl Grey', alias: 'A'},
{tea: 'Assam', alias: 'B'},
{tea: 'Black', alias: 'C'},
]
matchSorter(tea, 'A', {keys: ['tea', {maxRanking: matchSorter.rankings.STARTS_WITH, key: 'alias'}]})
// without maxRanking, Earl Grey would come first because the alias "A" would be CASE_SENSITIVE_EQUAL
// `tea` key comes before `alias` key, so Assam comes first even though both match as STARTS_WITH
// [{tea: 'Assam', alias: 'B'}, {tea: 'Earl Grey', alias: 'A'},{tea: 'Black', alias: 'C'}]
const tea = [
{tea: 'Milk', alias: 'moo'},
{tea: 'Oolong', alias: 'B'},
{tea: 'Green', alias: 'C'},
]
matchSorter(tea, 'oo', {keys: ['tea', {minRanking: matchSorter.rankings.EQUAL, key: 'alias'}]})
// minRanking bumps Milk up to EQUAL from CONTAINS (alias)
// Oolong matches as STARTS_WITH
// Green is missing due to no match
// [{tea: 'Milk', alias: 'moo'}, {tea: 'Oolong', alias: 'B'}]
number
Default: MATCHES
Thresholds can be used to specify the criteria used to rank the results. Available thresholds (from top to bottom) are:
const fruit = ['orange', 'apple', 'grape', 'banana']
matchSorter(fruit, 'ap', {threshold: matchSorter.rankings.NO_MATCH})
// ['apple', 'grape', 'orange', 'banana'] (returns all items, just sorted by best match)
const things = ['google', 'airbnb', 'apple', 'apply', 'app'],
matchSorter(things, 'app', {threshold: matchSorter.rankings.EQUAL})
// ['app'] (only items that are equal)
const otherThings = ['fiji apple', 'google', 'app', 'crabapple', 'apple', 'apply']
matchSorter(otherThings, 'app', {threshold: matchSorter.rankings.WORD_STARTS_WITH})
// ['app', 'apple', 'apply', 'fiji apple'] (everything that matches with "word starts with" or better)
boolean
Default: false
By default, match-sorter will strip diacritics before doing any comparisons. This is the default because it makes the most sense from a UX perspective.
You can disable this behavior by specifying keepDiacritics: true
const thingsWithDiacritics = ['jalapeño', 'à la carte', 'café', 'papier-mâché', 'à la mode']
matchSorter(thingsWithDiacritics, 'aa')
// ['jalapeño', 'à la carte', 'à la mode', 'papier-mâché']
matchSorter(thingsWithDiacritics, 'aa', {keepDiacritics: true})
// ['jalapeño', 'à la carte']
matchSorter(thingsWithDiacritics, 'à', {keepDiacritics: true})
// ['à la carte', 'à la mode']
In the examples above, we're using CommonJS. If you're using ES6 modules, then you can do:
import matchSorter, {rankings, caseRankings} from 'match-sorter'
Actually, most of this code was extracted from the very first library I ever wrote: genie!
You might try Fuse.js. It uses advanced math fanciness to get the closest match. Unfortunately what's "closest" doesn't always really make sense. So I extracted this from genie.
Thanks goes to these people (emoji key):
Kent C. Dodds 💻 📖 🚇 ⚠️ 👀 | Conor Hastings 💻 📖 ⚠️ 👀 | Rogelio Guzman 📖 | Claudéric Demers 💻 📖 ⚠️ | Kevin Davis 💻 ⚠️ | Denver Chen 💻 📖 ⚠️ | Christian Ruigrok 🐛 💻 📖 |
---|
This project follows the all-contributors specification. Contributions of any kind welcome!
MIT
FAQs
Simple, expected, and deterministic best-match sorting of an array in JavaScript
The npm package match-sorter receives a total of 1,540,382 weekly downloads. As such, match-sorter popularity was classified as popular.
We found that match-sorter demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.