1

Here is my array:

['California','Texas','Texas','Texas','New York','Missouri','New Mexico','California']

Is there a way in lodash to convert it to an object with a count of repeated occurrences like this:

[
    {'name':'California', 'count':2},
    {'name':'Texas', 'count':3},
    {'name':'New York', 'count':1},
    {'name':'Missouri', 'count':1},
    {'name':'New Mexico', 'count':1},
]

I have tried many combinations but have not been successful. Docs: https://lodash.com/docs#countBy

3
  • What have you tried? Seems to me that countBy works, you just have to slightly modify the result after it's done Commented Aug 30, 2016 at 16:11
  • Since you only have two properties maybe it would work better as {California: 2, Texas: 3} -- just a suggestion Commented Aug 30, 2016 at 16:18
  • @ExplosionPills this is exactly what countBy produces if you call it with no other arguments than the data in this post Commented Aug 30, 2016 at 16:20

6 Answers 6

4

You could just map the result of _.countBy.

var array = ['California','Texas','Texas','Texas','New York','Missouri','New Mexico','California'],
    count = _.countBy(array),
    result = _.map(count, (v, k) => ({ name: k, count: v }));

console.log(count);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

Combined with _.chain

var array = ['California','Texas','Texas','Texas','New York','Missouri','New Mexico','California'],
    count = _
        .chain(array)
        .countBy()
        .map((v, k) => ({ name: k, count: v }));

console.log(count);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

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

2 Comments

If you _.chain the calls, it'd be ever so slightly more performant, since you don't need the interim values. It makes the code look a bit tidier, too (again - no interim values). _.reduce might be a bit more idiomatic for this sort of thing.
Thanks for a solution with Lodash! Just a heads up, the variables 'k' and 'v' above need to switch. Otherwise it says: { name:3, count:'Texas' }
1

You can do this with reduce()

var ar = ['California','Texas','Texas','Texas','New York','Missouri','New Mexico','California'];

var obj = {}
var result = ar.reduce(function(r, e) {
  if(!obj[e]) {
    obj[e] = {name: e, count: 0};
    r.push(obj[e])
  }
  obj[e].count++;
  return r;
}, [])

console.log(result)

Comments

0

I am not sure there is a built-in function to achieve it, but you can do it using standard method.

var arr = ['California', 'Texas', 'Texas', 'Texas', 'New York', 'Missouri', 'New Mexico', 'California'];
var obj = [];

arr.forEach(a => {
    var b = obj.find(b => b.name == a);
    if(!b){
        obj.push({
            name: a,
            count: 1
        });
    }else{
        b.count++;
    }
});

console.log(JSON.stringify(obj, null, 2));

2 Comments

You can use find instead of filter. It more precisely what you want.
@Vld Updated answer.
0

As you said there's the countBy function for that, you have to map the result to set the format as required:

var result = _( array )
  .countBy( )
  .map( ( key, value ) => ( { name: key, count: value } ) )
  .value( )

console.log( result );

2 Comments

OP already mentioned it. Also, you don't need the second parameter - it defaults to the same.
right, I didn't noticed, I'll update the answer then
0

Pure JS in just two lines.

var arr = ['California','Texas','Texas','Texas','New York','Missouri','New Mexico','California'],
    lut = arr.reduce((p,c) => p[c] ? (p[c]++ ,p) : (p[c] = 1, p),{});
 result = Object.keys(lut).map(k => ({name:k,count:lut[k]}));
console.log(result);

Comments

0

In plain Javascript, you could use Array#forEach for it.

var data = ['toString', 'California', 'Texas', 'Texas', 'Texas', 'New York', 'Missouri', 'New Mexico', 'California'],
    count = [];

data.forEach(function (a) {
    if (!this[a]) {
        this[a] = { name: a, count: 0 };
        count.push(this[a]);
    }
    this[a].count++;
}, Object.create(null));

console.log(count)
.as-console-wrapper { max-height: 100% !important; top: 0; }

Version with {}

var data = ['toString', 'California', 'Texas', 'Texas', 'Texas', 'New York', 'Missouri', 'New Mexico', 'California'],
    count = [];

data.forEach(function (a) {
    if (!this[a]) {
        this[a] = { name: a, count: 0 };
        count.push(this[a]);
    }
    this[a].count++;
}, {}); // no Object.create(null)!

console.log(count)
.as-console-wrapper { max-height: 100% !important; top: 0; }

5 Comments

It would be better if you join your answers or delete this one.
Is there a reason why you use Object.create(null) and not just {}
@NenadVracar, you could count over toString and that would not go without a really empty object.
@NinaScholz The only property of an object created with {} is __proto__. Function toString is actually the property of {}.__proto__.constructor.prototype.
@SoftwareEngineer171, please watch the difference of example one and two. keep an eye on toString.

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.