2016-08-30 3 views
1

Вот мой массив:Lodash: Преобразовать массив с повторяющимися значениями объекта с числом повторных вхождений

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

Есть ли способ в lodash, чтобы преобразовать его в объект с отсчетом повторных вхождений, как это:

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

Я пробовал много комбинаций, но не был успешным. Документы: https://lodash.com/docs#countBy

+0

Что вы пробовали? Мне кажется, что 'countBy' работает, вам просто нужно слегка изменить результат после его завершения. – vlaz

+0

Поскольку у вас есть только два свойства, возможно, это будет работать лучше, чем' {California: 2, Texas: 3} '- просто предложение –

+0

@ExplosionPills это именно то, что 'countBy' производит, если вы вызываете его без каких-либо других аргументов, чем данные в этом сообщении. – vlaz

ответ

4

Вы можете просто отобразить результат _.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>

В сочетании с _.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>

+1

Если вы '_.chain' вызовы, это будет настолько немного более результативным, поскольку вам не нужны промежуточные значения. Это делает код немного более аккуратным (опять же - без промежуточных значений). '_.reduce' может быть немного более идиоматичным для такого рода вещей. – vlaz

+1

Спасибо за решение с Lodash! Просто голова, переменные «k» и «v» выше должны переключаться. В противном случае он говорит: {name: 3, count: 'Texas'} – ndcomix

0

Я не уверен, что для его достижения есть встроенная функция, но вы можете сделать это с использованием стандартного метода.

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)); 
+0

Вы можете использовать' find' вместо 'filter'. Это более точно, чего вы хотите. – vlaz

+0

@ Vld Обновленный ответ. –

1

Вы можете сделать это с 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)

0

Как вы сказали, что есть функция countBy для этого, вы должны сопоставить результат, чтобы установить формат в соответствии с требованиями:

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

console.log(result); 
+0

ОП уже упоминал об этом. Кроме того, вам не нужен второй параметр - по умолчанию он одинаковый. – vlaz

+0

Право, я не заметил, я обновлю ответ, тогда – Motocarota

0

В простом Javascr ipt, вы можете использовать для этого Array#forEach.

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; }

Версия с {}

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; }

+0

Было бы лучше, если вы присоединитесь к своим ответам или удалите этот. –

+0

Есть ли причина, по которой вы используете 'Object.create (null)', а не только '{}' –

+0

@NenadVracar, вы можете рассчитывать на 'toString', и это не будет идти без действительно пустого объекта. –

0

Pure JS всего две линии.

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);