2

I want to filter an array of urls by excluding ones that contain any substrings that are in a blacklist array.

const urls = [
'http://example.com/people/chuck', 
'http://example.com/goats/sam', 
'http://example.com/goats/billy', 
'http://example.com/goats/linda', 
'http://example.com/cows/mary', 
'http://example.com/cows/betty', 
'http://example.com/people/betty']

const blacklist = ['cows', 'goats']

let cleanUrls = [];

I can do this with for-loops but I want to find a clean/concise way using filter and/or reduce.

If I didn't need to loop over x number of blacklist items:

cleanUrls = urls.filter( url => !url.includes(blacklist[0]) )                  
                .filter( url => !url.includes(blacklist[1]) ) 

I also don't want to just iterate through the blacklist with a forEach or map because I want to immediately stop if a particular url matches any blacklist entry.

Plain JS please. Thank you. :)

1
  • urls.some(url => blacklist.includes(url)) Commented Mar 29, 2018 at 17:03

6 Answers 6

7

You can use filter() like this:

const cleanUrls = urls.filter(u => blacklist.every(s => !u.includes(s)));

Or

const cleanUrls = urls.filter(u => !blacklist.some(s => u.includes(s)));

Description:

  • .includes() will check the existence of a sub-string withing another string.
  • .every() will check whether none of the strings of blacklist array exists in a particular URL.
  • .some() will check whether any of the string of blacklist array exists in a particular URL.
  • .filter() will select only those URL's which will pass the test.

Demo:

const urls = [
  'http://example.com/people/chuck', 
  'http://example.com/goats/sam', 
  'http://example.com/goats/billy', 
  'http://example.com/goats/linda', 
  'http://example.com/cows/mary', 
  'http://example.com/cows/betty', 
  'http://example.com/people/betty'
];

const blacklist = ['cows', 'goats'];

const cleanUrls = urls.filter(u => blacklist.every(s => !u.includes(s)));

console.log(cleanUrls);

Docs:

Sign up to request clarification or add additional context in comments.

4 Comments

I think you mean some not every
@HunterMcMillen Yes, I just thought some but mistakenly wrote another.
To Downvoter: May I know the reason of your downvote?
@HunterMcMillen By the way, every() will work too and it seems more appropriate as compared to some()
1

You can do this with filter(), some() and includes() methods.

const urls = ['http://example.com/people/chuck', 'http://example.com/goats/sam', 'http://example.com/goats/billy', 'http://example.com/goats/linda', 'http://example.com/cows/mary', 'http://example.com/cows/betty', 'http://example.com/people/betty'];
const blacklist = ['cows', 'goats']

const result = urls.filter(url => !blacklist.some(e => url.includes(e)))

console.log(result)

Comments

0

It might be easuer to turn the blacklist i to a Regex:

 const block = new RegExp(blacklist.join("|"));

Them its as simple as:

 cleanUrls = urls.filter(url => !url.match(block));

Comments

0

You can use forEach & indexOf to check if the element from second array is present in the url

const urls = [
  'http://example.com/people/chuck',
  'http://example.com/goats/sam',
  'http://example.com/goats/billy',
  'http://example.com/goats/linda',
  'http://example.com/cows/mary',
  'http://example.com/cows/betty',
  'http://example.com/people/betty'
]

const blacklist = ['cows', 'goats'];

var newArray = [];
blacklist.forEach(function(item) {
  if (newArray.length === 0) {
    newArray = urls.filter(function(items) {
      return (items.indexOf(item) === -1)

    })

  } else {
    newArray = newArray.filter(function(items) {
      return (items.indexOf(item) === -1)
    })
  }
});
console.log(newArray)

Comments

0

I also don't want to just iterate through the blacklist with a forEach or map because I want to immediately stop if a particular url matches any blacklist entry.

The function stop searching if an element from the blacklist appears.

Recursive way to solve this problem:

const urls = [
'http://example.com/people/chuck', 
'http://example.com/goats/sam', 
'http://example.com/goats/billy', 
'http://example.com/goats/linda', 
'http://example.com/cows/mary', 
'http://example.com/cows/betty', 
'http://example.com/people/betty']

const blacklist = ['cows', 'goats']

function filter([url, ...urls] =[], blackList=[], filteredUrls =[] ){
	return !url || blacklist.some(el => url.includes(el)) 
        ? filteredUrls 
        : filter(urls, blackList, [...filteredUrls, url])
}

console.log(filter(urls, blacklist));

Comments

0

Others have answered the question. Providing two different scenarios.

const urls = [
  'http://example.com/people/chuck',
  'http://example.com/goats/billy',
  'http://example.com/aagoatsss/billyyy',
  'http://example.com/people/betty'
]

const blacklist = ['cows', 'goats']

//1st approach. It will also block 'http://example.com/aagoatsss/billyyy'
let cleanUrls1 = urls.filter(
  url => blacklist.find(
    blockWord => url.indexOf(blockWord) != -1 //Url contains Block Word
  ) === undefined //url donot contain any block word.
)

console.log(cleanUrls1)

//2nd approach. It will pass 'http://example.com/aagoatsss/billyyy'

let cleanUrls2 = urls.filter(
  url => blacklist.find(
    blockWord => url.split('/').indexOf(blockWord) != -1 //Url contains Block Word
  ) === undefined //url donot contain any block word.
)
console.log(cleanUrls2)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.