Search code examples
javascriptarraysecmascript-5

Refine nested loop to filter objects containing certain value, from array


In JavaScript, I have an array of objects:

var allAliases = [
  { "name": "Cards", "alias": "cards", "view": "/path/cards/" },
  { "name": "Carousel", "alias": "carousel", "view": "/path/carousel/" },
  { "name": "Image boxes", "alias": "imageBoxes", "view": "/path/imageBoxes/" },
  { "name": "Gallery", "alias": "gallery", "view": "/path/gallery/" },
  { "name": "Slide panels", "alias": "slidePanels", "view": "/path/slide-panels/" }
]

I then have a string array of aliases, like this:

var aliases = 'cards,carousel,gallery';
var permittedAliases = aliases.split(',');

I need to filter the original array such that I'm left with only the objects whose alias value matches and of the strings in the permittedAliases array. So in the case above I'd be left with:

[
  { "name": "Cards", "alias": "cards", "view": "/path/cards/" },
  { "name": "Carousel", "alias": "carousel", "view": "/path/carousel/" },
  { "name": "Gallery", "alias": "gallery", "view": "/path/gallery/" }
]

I can do this by creating a new array, looping through the original array, comparing values and adding matched objects to the new array like this:

var filteredArray = [];

for (var i = 0; i < allAliases.length; i++) {
    for (j = 0; j < permittedAliases.length; j++) {
        if (allAliases[i].alias === permittedAliases[j]) {
            filteredArray.push(allAliases[i]);
        }
    }
}

This just feels very clunky to me though, loops within loops. I wondered if there's a neater way to do it?

The constraint is that it needs to be ES5.1 unfortunately.

Many thanks.


Solution

  • You could filter the array with Array#filter and Array#some for the aliasses.

    var allAliases = [{ "name": "Cards", "alias": "cards", "view": "/path/cards/" }, { "name": "Carousel", "alias": "carousel", "view": "/path/carousel/" }, { "name": "Image boxes", "alias": "imageBoxes", "view": "/path/imageBoxes/" }, { "name": "Gallery", "alias": "gallery", "view": "/path/gallery/" }, { "name": "Slide panels", "alias": "slidePanels", "view": "/path/slide-panels/" }],
        aliases = 'cards,carousel,gallery',
        permittedAliases = aliases.split(','),
        filtered = allAliases.filter(function (o) {
            return permittedAliases.some(function (a) {
                return o.alias === a;
            });
        });
    
    console.log(filtered);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    Or you could use Array#indexOf, instead of Array#some

    var allAliases = [{ "name": "Cards", "alias": "cards", "view": "/path/cards/" }, { "name": "Carousel", "alias": "carousel", "view": "/path/carousel/" }, { "name": "Image boxes", "alias": "imageBoxes", "view": "/path/imageBoxes/" }, { "name": "Gallery", "alias": "gallery", "view": "/path/gallery/" }, { "name": "Slide panels", "alias": "slidePanels", "view": "/path/slide-panels/" }],
        aliases = 'cards,carousel,gallery',
        permittedAliases = aliases.split(','),
        filtered = allAliases.filter(function (o) {
            return permittedAliases.indexOf(o.alias) !== -1;
        });
    
    console.log(filtered);
    .as-console-wrapper { max-height: 100% !important; top: 0; }