2
\$\begingroup\$

I have an Array of objects, each which contain their own sub Tags Array, and I need to loop through and find a matching id.

Array: [
    Object {
        tags: [
            { tag_id: 1 },
            { tag_id: 2 }
        ]
        name: name_1
    },
    Object {
        tags: [
            { tag_id: 3 },
            { tag_id: 4 },
            { tag_id: 5 }
        ]
        name: name_2
    }
]

I have a click action when sends in 1 tag from the page to compare and I need to check it's ID to the id of all tags in the larger array.

This is what I have so far which works, but is there a cleaner, simpler more efficient way to do this? With a hashtable perhaps? If so, how?

// I get the large stored Array to compare too:
var tagObjects = TagFactory.retrieveTags();
var index = -1;
var temp_tags = [];

// tagObj is the single tag that is sent from the markup to check:
// Below is what I'm trying to find in the larger array:
console.log(tagObj.tag_id);

// Checking if the large Array has anything
if (tagObjects.length > 0) {

    // I go through and separate the smaller tag Arrays out:
    for (var i = 0; i < tagObjects.length; i++) {
        temp_tags.push(tagObjects[i].tags);
    }

    // Finally I try to find the ID inside of the temp_tags Array:
    for (var i = 0; i < temp_tags[0].length; i++) {
        if (tagObj.tag_id === temp_tags[0][i].tag_id) {
            console.log('found id YEAH!');
            index = 1;
        }
    }
}

// If I found the ID, it means I can remove the tag
if (index !== -1) {
    tagObj.selected = false;
    TagFactory.removeTags(tagObj);
}

// If I did not find the ID, it means I can add it
// Add tag:
else {
\$\endgroup\$
4
  • \$\begingroup\$ this array looks like JSON. you may want to use the ECMA 5 standard included JSON.parse() to get nicer objects to search through ;) \$\endgroup\$
    – Vogel612
    Apr 30, 2015 at 14:51
  • \$\begingroup\$ O I guess it does hehe, but it's an Array I make... basically I stuff a prototyped object into it. And those Objects have a name, as well as an array of tags. \$\endgroup\$
    – Leon Gaban
    Apr 30, 2015 at 14:56
  • \$\begingroup\$ @Vogel612 do you have a good example? \$\endgroup\$
    – Leon Gaban
    Apr 30, 2015 at 15:25
  • 2
    \$\begingroup\$ index = 1; shouldn't it be index = i;? \$\endgroup\$
    – sigod
    Apr 30, 2015 at 15:30

2 Answers 2

3
\$\begingroup\$

I cannot say about AngularJS, but in normal JavaScript I would do something like this:

var tagObjects = TagFactory.retrieveTags();

if (findTag(tagObjects, tagObj.tag_id)) {
    // remove tag
}
else {
    // add tag
}


function findTag(tagObjects, tag_id) {
    return tagObjects
        .reduce(function (total, obj) { return total.concat(obj.tags); }, [])
        .find(function (tag) { return tag.tag_id === tag_id; })
    ;
}

Note that find is a part of upcoming es6 standard. So you might need to use es6-shims (like I do) or write your own version. It's very easy.

Or, if TagFactory.retrieveTags() returns some special structure — shouldn't it also provide findTag method?

\$\endgroup\$
7
  • \$\begingroup\$ Welcome to CodeReview, sigod. I hope you enjoy the site. \$\endgroup\$
    – Legato
    Apr 30, 2015 at 16:31
  • \$\begingroup\$ Thanks, but I just got error: TypeError: tagObjects.reduce(...).find is not a function on the .find line. \$\endgroup\$
    – Leon Gaban
    Apr 30, 2015 at 16:42
  • \$\begingroup\$ @LeonGaban Read my note in the answer. \$\endgroup\$
    – sigod
    Apr 30, 2015 at 16:59
  • \$\begingroup\$ @sigod found it! Just installed it via bower-installer too :) trying it out again \$\endgroup\$
    – Leon Gaban
    Apr 30, 2015 at 17:06
  • \$\begingroup\$ @sigod ugh now getting this error: Cannot read property 'reduce' of undefined Is there another shim I need? \$\endgroup\$
    – Leon Gaban
    Apr 30, 2015 at 17:16
3
\$\begingroup\$

A more functional approach:

var tag = ...; // the tag to look for
var tagObjects = TagFactory.retrieveTags();

var foundTag = tagObjects.some(function (obj) {
  return obj.tags.some(function (tagObj) {
    return tagObj.tag_id === tag.tag_id;
  });
});

if(foundTag) {
  // the tag exists...
} else {
  // it doesn't...
}

Array.prototype.some basically loops through the array it's called on, and returns true if the callback returns true for any of the elements.

In your code, there's no reason to first collect all the nested tags from tagObjects; easier to dive into each collection, and check the nested tags.

Of course, if you need the full list for something else anyway, you could get the master list with Array.prototype.reduce:

var allTags = tagObjects.reduce(function (memo, obj) {
  return memo.concat(obj.tags);
}, []);

var foundTag = allTags.some(function (tagObj) {
  return tagObj.tag_id = tag.tag_id;
});
\$\endgroup\$
0

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.