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\$
  • \$\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 '15 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 '15 at 14:56
  • \$\begingroup\$ @Vogel612 do you have a good example? \$\endgroup\$ – Leon Gaban Apr 30 '15 at 15:25
  • 2
    \$\begingroup\$ index = 1; shouldn't it be index = i;? \$\endgroup\$ – sigod Apr 30 '15 at 15:30
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?

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Welcome to CodeReview, sigod. I hope you enjoy the site. \$\endgroup\$ – Legato Apr 30 '15 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 '15 at 16:42
  • \$\begingroup\$ @LeonGaban Read my note in the answer. \$\endgroup\$ – sigod Apr 30 '15 at 16:59
  • \$\begingroup\$ @sigod found it! Just installed it via bower-installer too :) trying it out again \$\endgroup\$ – Leon Gaban Apr 30 '15 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 '15 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;
});
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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