lodash / underscore查找数组中非唯一元素的数量

时间:2015-09-06 12:22:41

标签: javascript arrays underscore.js lodash

我有一个包含一定数量字符串的数组,我需要找出有多少字符串不唯一 - 与_.uniq相反。我已经尝试了一些事情,但到目前为止已经提出了死胡同。我觉得答案很简单。举个例子:

/**
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\ManyToMany(targetEntity="Application\Entity\Role")
     * @ORM\JoinTable(name="user_role_linker",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
     * )
     */
    protected $roles;

我想从这里得到2的答案,因为只有两个字符串在数组中不止一次。

3 个答案:

答案 0 :(得分:5)

var list = ["abc", "abc", "def", "rty", "rty", "rty", "uig", "ghe", "bed", "abc"];

var repeatedCount = _.filter(_.groupBy(list), function(n) { return n.length > 1; }).length;

答案 1 :(得分:2)

所以,您正在寻找一种廉价的跨浏览器解决方案来解决您的问题?通过使用为ES3 +设计的下划线或lodash。但是,您必须小心列表中的字符串。

让我们来看看MinusFour的答案。

var $countOfLikeStrings3 = function(arrayOfStrings) {
  var repeated = {
    length: 0
  };

  _.reduce(arrayOfStrings, function(acc, val) {
    if (acc[val] !== undefined) {
      if (repeated[val] === undefined) {
        repeated[val] = true;
        repeated.length++;
      }
    }

    acc[val] = true;

    return acc;
  }, {});

  return repeated.length;
}

var pre = document.getElementById('out');

function log(result) {
  pre.appendChild(document.createTextNode(result + '\n'));
}

var list1 = ['length', 'length', 'constructor', 'constructor', 'prototype', 'prototype', '__proto__', '__proto__'];

log($countOfLikeStrings3(list1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<pre id="out"></pre>

我想我们没想到1的结果?

现在的aquinas解决方案。

var $countOfLikeStrings2 = function(arrayOfStrings) {
  return _.filter(_.groupBy(arrayOfStrings), function(n) {
    return n.length > 1;
  }).length;
}

var pre = document.getElementById('out');

function log(result) {
  pre.appendChild(document.createTextNode(result + '\n'));
}

var list1 = ['length', 'length', 'constructor', 'constructor', 'prototype', 'prototype', '__proto__', '__proto__'];

log($countOfLikeStrings2(list1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<pre id="out"></pre>

再次,没想到3?

好的,现在让我们使用一些现代的ES6,这样可以减少浏览器支持,但这可以在当前的主流浏览器和节点上运行。

var $countOfLikeStrings1 = (function(create) {
  'use strict';

  var symRepeated = Symbol('repeated'),
    symLength = Symbol('length');

  return function(arrayOfStrings) {
    var accumulator = create(null);

    accumulator[symRepeated] = create(null);
    accumulator[symRepeated][symLength] = 0;

    return arrayOfStrings.reduce(function(acc, stringItem) {
      var repeated = acc[symRepeated],
        count = (acc[stringItem] || 0) + 1;

      acc[stringItem] = count;
      if (count > 1) {
        if (!repeated[stringItem]) {
          repeated[symLength] += 1;
        }

        repeated[stringItem] = count;
      }

      return acc;
    }, accumulator)[symRepeated][symLength];
  };
}(Object.create));

var pre = document.getElementById('out');

function log(result) {
  pre.appendChild(document.createTextNode(result + '\n'));
}

var list1 = ['length', 'length', 'constructor', 'constructor', 'prototype', 'prototype', '__proto__', '__proto__'];

log($countOfLikeStrings1(list1));
<pre id="out"></pre>

喂!那更像是它,4!

所以,在ES6中甚至可能有更好的方法 - 我还在学习新东西。通过一些额外的ES3和ES5代码,另外两个解决方案也可以得到改进。

除了这些问题之外,这里有三个解决方案jsPerf

更新:重新设计为更多ES6

function $countOfLikeStrings4(arrayOfStrings) {
  'use strict';

  const accumulator = new Map(),
    repeated = new Map();

  var oldCount,
    newCount;

  for (let stringItem of arrayOfStrings) {
    oldCount = accumulator.get(stringItem) || 0;
    newCount = oldCount + 1;
    accumulator.set(stringItem, newCount);
    if (newCount > 1 && !repeated.has(stringItem)) {
      repeated.set(stringItem, true);
    }
  }

  return repeated.size;
}

var pre = document.getElementById('out');

function log(result) {
  pre.appendChild(document.createTextNode(result + '\n'));
}

var list1 = ['length', 'length', 'constructor', 'constructor', 'prototype', 'prototype', '__proto__', '__proto__'];

log($countOfLikeStrings4(list1));
<pre id="out"></pre>

答案 2 :(得分:1)

这是使用underscore执行此操作的一种方法。您只需继续在累加器上搜索重复值,并将非唯一项添加到另一个对象/数组。注意:这仅适用于字符串数组。

&#13;
&#13;
var list = ["eyxCyqqbn3", "jPEbM00mvQ", "5pi7wTh689", "P2iBGGwuWZ", "eyxCyqqbn3", "jPEbM00mvQ", "uX1GrD4UQt", "uX1GrD4UQt", "uX1GrD4UQt", "uX1GrD4UQt", "uX1GrD4UQt", "yXkmkZo0lW", "5pi7wTh689", "P2iBGGwuWZ", "uX1GrD4UQt", '__proto__', '__proto__'];
var repeated = Object.create(null);
_.reduce(list, function(acc, val) {
  if (Object.prototype.hasOwnProperty.call(acc, val)) {
    if (!Object.prototype.hasOwnProperty.call(repeated, val)) {
      repeated[val] = true;
    }
  }
  acc[val] = true;
  return acc;
}, Object.create(null));

var amountrepeated = Object.keys(repeated).length;

document.getElementById('results').innerHTML = amountrepeated;
&#13;
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<pre id="results"></pre>
&#13;
&#13;
&#13;