Javascript filter array with multiple lines

Hello

im trying to filter arrays with named products that are filled with 1 row per product.

var products = [
    'canadian black angus beef fresh',
    'canadian black angus beef frozen',
    'american black angus beef frozen'
];

      

The search begins by splitting the elemnt input form with spaces in an array with names that contain variable length strings.

var keywords = ['angus', 'fresh'];

      

Actually im for-looping product_array and make a 2nd (inner) for loop for the keyword. Everything is fine so far.

here is my shorthand code that shows the problem:

function test() {

    var products = [
        'canadian black angus beef fresh',
        'canadian black angus beef frozen',
        'american black angus beef frozen'
    ];

    var keywords = ['angus', 'fresh'];
    var hits = [];

    for (var i = 0; i < products.length; i++) {

        for (var j = 0; j < keywords.length; j++) {

            if (products[i].indexOf(keywords[j]) != -1) {

                /*
                a if case for looped '&&' operator 
                would be great - or something like that
                looped because of the variable length of keywords
                */
                hits.push(products[i]);

            }

        }

    }

    console.log(hits);
    /* 
    all products :/ - because all product matches with 'angus'
    but im searching for an product that contains 'angus' && 'fresh'
    */

}

      

some ideas ?!

+3


source to share


4 answers


Just put a flag that checks if you have all the keywords:

var containsAll;

for (var i = 0; i < products.length; i++) {

    // Initialize flag -> guess that this product is correct
    containsAll = true;
    for (var j = 0; j < keywords.length; j++) {
        if (products[i].indexOf(keywords[j]) === -1) {
            // This keyword is not matched -> incorrect product
            containsAll = false;
            break;
        }
    }

    // All products has been matched
    if (containsAll) hits.push(products[i]);
}

      



See this fiddle: http://jsfiddle.net/eoz1y8n4/

+1


source


You just need to make sure your product has all the keywords in it:



function test() {

    var products = [
        'canadian black angus beef fresh',
        'canadian black angus beef frozen',
        'american black angus beef frozen'];

    var keywords = ['angus', 'fresh'];
    var hits = [];

    for (var i = 0; i < products.length; i++) {
        var allKeywordsMatch = true;
        for (var j = 0; j < keywords.length; j++) {

            if (products[i].indexOf(keywords[j]) === -1) {

                allKeywordsMatch = false;
                break;
            }

        }

        if (allKeywordsMatch) hits.push(products[i]);

    }

    alert(hits);
}


test();
      

Run codeHide result


+1


source


First of all, you should take a look at the function .filter()

. It iterates through the array and returns the elements you want based on the true / false return of the conditions you set.

MDN docs on Array.prototype.filter ()

Now, to be sure that both keywords exist, you can use some flag to indicate what it does or does not do:

var hits = products.filter(function(item) {
    var valid = true;
    for (var i = 0; i < keywords.length; i++) {
        if (item.indexOf(keywords[i]) === -1) {
            valid = false;
        }
    }

    return valid;
});

      

+1


source


This thread helped me a lot to achieve my desired search result, and based on that, I extended the above solution to search in an array of objects and multiple fields like title, category or tags.

I am posting my answer with code just to help if any developer needs it. However, there is a chance for further improvements and I hope it will be helpful to someone.

My requirement was:

  • To find words to search for in a title (string), category (string), or an array of tags (array of strings).
  • Search words can be multiples of a space, for example "Es6 IIFE"
  • Search words can appear anywhere in the string in any order.

I have prepared one live demo for the same. You can run and check the result.

I have the following sample array of articles listing objects .

let articles = [
            { "title": "ES6 — set, map, weak", "category": "ES6", "tags": ["ES6", "Set", "Map", "Weak"] },
            { "title": "JavaScript Modules: From IIFEs to CommonJS to ES6 Modules", "category": "JavaScript", "tags": ["JavaScript", "Modules", "IIFE", "ES6 Modules"] },
            { "title": "A guide to JavaScript Regular Expressions", "category": "JavaScript", "tags": ["JavaScript", "RegExp", "Regular Expressions"] },
        ];

      

If a person types "es6 iife" in the search field and clicks the button, he will first look through the array of tags, if not found there, he will look for the title and category.

let output = document.querySelector('#output');
let articles = [
	{ "title": "ES6 — set, map, weak", "category": "ES6", "tags": ["ES6", "Set", "Map", "Weak"] },
	{ "title": "JavaScript Modules: From IIFEs to CommonJS to ES6 Modules", "category": "JavaScript", "tags": ["JavaScript", "Modules", "IIFE", "ES6 Modules"] },
	{ "title": "A guide to JavaScript Regular Expressions", "category": "JavaScript", "tags": ["JavaScript", "RegExp", "Regular Expressions"] },
];

let initialContent = '';
articles.map(article => {
	initialContent += '<li>
		<p><b>Title : </b> ${article.title}</p>
		<p><b>Category : </b> ${article.category}</p>
		<p><b>Tags : </b> ${article.tags}</p>
		</li>';
});

output.innerHTML = initialContent;

function filter() {
	let searchTerm = document.querySelector('#searchBox').value;
	let keywords = searchTerm.split(' ');
	let articleBySearch = [];

	articles.map((article) => {
		let allKeywordsMatch = true;

		keywords.map((keyword) => {
			if (article.tags.some((tag) => tag.toLowerCase().indexOf(keyword.toLowerCase()) !== -1)) {
				allKeywordsMatch = true;
			} else {
				if (article.title.toLowerCase().indexOf(keyword.toLowerCase()) === -1 && article.category.toLowerCase().indexOf(keyword.toLowerCase()) === -1) {
					allKeywordsMatch = false;
				}
			}
		});

		if (allKeywordsMatch) articleBySearch.push(article);
	});

	// Display Output in the browser
	let htmlContent = '';
	articleBySearch.map(article => {
		htmlContent += '<li>
		<p><b>Title : </b> ${article.title}</p>
		<p><b>Category : </b> ${article.category}</p>
		<p><b>Tags : </b> ${article.tags}</p>
		</li>';
	});

	output.innerHTML = htmlContent;
}
      

body {
	font-family: Arial, Helvetica, sans-serif;
	font-size: 16px;
}

.example {
	border: 1px solid rgb(245, 28, 118);
	width: 400px;
	margin: 0 auto;
	padding: 1em;
}

.example #searchBox {
	padding: 10px;
	border: 1px solid #cccccc;
}

.example #searchBox:focus {
	padding: 10px;
	border: 1px solid #0059ff;
}

.example button {
	padding: 10px;
	color: #FFF;
	background-color: #0059ff;
	border: 1px solid #0059ff;
}

.example ul {
	margin: 0;
	padding: 0;
	list-style: none;
}

.example li {
	border: 1px solid #cccccc;
	padding: 1em;
	margin: 1em 0;
}
      

<div class="example">
		<input type="text" id="searchBox" placeholder="Type your words to search" />
		<button onClick="filter()">Click to Filter</button>
		<ul id="output"></ul>
</div>
      

Run codeHide result


0


source







All Articles