ksumarine
ksumarine

Reputation: 782

Turn array of comma delimited strings into distinct array

I would like to take an array of objects:

var objArr = [
    {id:1, name:'test', seenby:'user1, user2, user3'},
    {id:2, name:'test1', seenby:'user3, user4'},
    {id:3, name:'test2', seenby:'user1, user3'},
    {id:4, name:'test3', seenby:'user2'}
];

And return a distinct array of all 'seenby' users:

var seenByArr = ['user1', 'user2', 'user3', 'user4']

I can't figure out how to efficiently (fewest lines possible) turn this into an array of distinct values. Please check out my fiddle for an example: https://jsfiddle.net/ksumarine/ss3v7dgj/

Upvotes: 3

Views: 1190

Answers (6)

Maze
Maze

Reputation: 726

I would use the Array.prototype.map function, and de-duplicate the users in a associative array. So here the interesting part, but you can also try it out here:

var list = [
    {id:1, name:'test', seenby:'user1, user2, user3'},
    {id:2, name:'test1', seenby:'user3, user4'},
    {id:3, name:'test2', seenby:'user1, user3'},
    {id:4, name:'test3', seenby:'user2'}
];

var arr = [];
list.map(function(value){
        value.seenby.split(",").map(function(val){
      arr[val.trim()] = 1;
        });
});

var seenby = Object.keys(arr);

How does it work? The map function will iterate over all the list items, the next map will iterate over all the seenby items. We then collect the users in the arr, de-duplicating by using it as an associative array. At the end we extract all the associative array keys by using the Object.keys function.

Minor caveat is that this solution will only work if the map function exists, if it doesn't you would need to implement it yourself. But usually you are using a new enough JavaScript version that does support it. This solution also has the nice side effect that you don't really need any external dependency (except of course for displaying it)

UPDATE: I think it's actually better to do it the following way:

var arr = list
    .reduce(function(acc, value){
        return acc.concat(value.seenby.split(",").map(function(val){
            return val.trim()
    }))},[])
    .filter(function(item, index, array) {
        return array.indexOf(item) === index
    }
)

Explanation:

  • we take the list and for each item, we reduce it ...
    • from each item, we extract the seenby field
    • we split the field
    • we map each item to trim it
  • ... we take the array of returned seenby and concatenate them to our accumulator array arr (which is initialized as empty array [])
  • then we filter out the duplicates from the array (by checking whether the index of an item is the same as the current index)

Upvotes: 1

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

The laconic solution with String.split and Array.foreach functions:

var arr = [];
objArr.forEach(function (obj) {
        var str = obj.seenby.split(',');
        str.forEach(function (v) {
            var user = v.trim();
            if (arr.indexOf(user) === -1) arr.push(user);
        });
});

console.log(arr);
// the output:
["user1", "user2", "user3", "user4"]    

Upvotes: 2

georg
georg

Reputation: 214959

given = function (x) {
    return {
        do: function (f) { x = f(x); return this },
        return: function () { return x }
    }
};

r = given(objArr)
    .do(x => x.map(y => y.seenby))
    .do(x => [].concat.apply([], x))
    .do(x => x.join(', '))
    .do(x => x.split(', '))
    .do(x => x.filter((e, i) => x.indexOf(e) === i))
    .do(x => x.sort())
    .return();

I might find use for this someday...

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386624

A solution in plain Javascript with an IIFE and a temporary object for the items.

var objArr = [{ id: 1, name: 'test', seenby: 'user1, user2, user3' }, { id: 2, name: 'test1', seenby: 'user3, user4' }, { id: 3, name: 'test2', seenby: 'user1, user3' }, { id: 4, name: 'test3', seenby: 'user2' }],
    result = function (array) {
        var obj = {}, r = [];
        array.forEach(function (a) {
            a.seenby.split(', ').forEach(function (b) {
                obj[b] = obj[b] || r.push(b);
            });
        });
        return r;
    }(objArr);

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

Upvotes: 1

Nikhil Aggarwal
Nikhil Aggarwal

Reputation: 28455

You can try following

$.each(list, function(index, value) {
    $.each(value.seenby.split(","), function(i, val) {
        if (val !== undefined && val.trim() !== "" && arr.indexOf(val.trim()) == -1) {
            arr.push(val.trim());
        }
    });
});

For reference - https://jsfiddle.net/ss3v7dgj/1/

Upvotes: 1

Emmett
Emmett

Reputation: 14327

I realize this question doesn't mention Underscore, but it's worth mentioning that Underscore.js is a very popular library for manipulating objects and arrays, and well-suited for this kind of thing.

Here's a big unreadable single line for achieving this with Underscore:

_.unique(_.flatten(_.map(_.pluck(objArr, 'seenby'), function(seenby) { return seenby.split(', '); })))

Upvotes: 3

Related Questions