Reputation:
I have an input box that filters an array and only shows those matches.
let songs = [
{name: 'Let It Be', artist: 'The Beatles},
{name: 'Lady Madonna', artist: 'The Beatles },
{name: 'Mama Mia', artist: 'The Beatles}
];
In the following example it will just match by name.
let value = 'name';
let q = 'Let it be' // value entered in input box;
let songFilter = songs.filter(function(song) {
return song[value].toString().toLowerCase().indexOf(q) != -1; // returns true or false
});
Then when I enter Let It Be
into the input box it will show return just 'Let It Be'
. However, I want to filter by two songs, so if I enter Let It Be, Lady Madonna
I would like it to return two songs.
I have taken many approaches but cannot figure out how to get this working. I also have lodash
available if this makes it easier to solve.
Upvotes: 1
Views: 3641
Reputation: 21
let songs = [
{ name: 'Let It Be', artist: 'The Beatles' },
{ name: 'Lady Madonna', artist: 'The Beatles' },
{ name: 'Mama Mia', artist: 'The Beatles' }
];
let value = 'name';
let q = 'Let it be, Lady madonna';
let songFilter = _.filter(songs, (song) => {
let regex = new RegExp(q.replace(/\s*,\s*/g, '|'), 'gi');
return regex.test(song[value]);
});
console.log(songFilter);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Upvotes: 0
Reputation: 350760
You could use a Set
to key the entries (after split
) that have been input. That way you can see in constant time whether there is a match. Here that Set
is passed to filter
as the context, so it can be referenced with this
:
let songs = [
{name: 'Let It Be', artist: 'The Beatles' },
{name: 'Lady Madonna', artist: 'The Beatles' },
{name: 'Mama Mia', artist: 'The Beatles' }
];
function find(byKey, valueCsv) {
return songs.filter(function(song) {
return this.has(song[byKey].toLowerCase())
}, new Set(valueCsv.trim().toLowerCase().split(/\s*,\s*/)));
}
songInput.addEventListener('input', function() {
matches.textContent = JSON.stringify(find('name', songInput.value), null, 2);
});
Type song name(s):<input id="songInput" style="width:100%">
<pre id="matches"></pre>
Upvotes: 1
Reputation: 31712
As I said in the comment above:
let songs = [
{name: 'Let It Be', artist: 'The Beatles'},
{name: 'Lady Madonna', artist: 'The Beatles'},
{name: 'Mama Mia', artist: 'The Beatles'}
];
let value = 'name';
let q = 'Let it be, Lady madonna';
// First: split the q value into multiple songs (and make them lowercased)
let qSongs = q.split(', ').map(e => e.toLowerCase());
// Second: filter song that are in the above resultant array (qSongs)
// for each song in the songs array
let songFilter = songs.filter(song =>
// see if there is some qsong in the qSongs array such that the value of song is equal to qsong
qSongs.some(qsong =>
song[value].toLowerCase().indexOf(qsong) != -1
)
);
console.log(songFilter);
Upvotes: 0
Reputation: 13953
using Array#filter
and Array#find
let songs = [
{name: 'Let It Be', artist: 'The Beatles'},
{name: 'Lady Madonna', artist: 'The Beatles' },
{name: 'Mama Mia', artist: 'The Beatles'}
];
let value = 'name';
let q = 'Let it be,Lady Madonna' // value entered in input box;
let splitQ = q.split(',').map(sq=>sq.toLowerCase());
let songFilter = songs.filter(s=>splitQ.find(sq=>s[value].toLowerCase().indexOf(sq) > -1 ) !== undefined );
console.log(songFilter);
Upvotes: 0
Reputation: 4310
let songFilter = songs.filter(function(song) {
['let it be', 'lady madonna'].indexOf(song[value].toString().toLowerCase()) > -1
});
Upvotes: 1