比较同一数组元素的最快方法

时间:2019-06-24 11:00:35

标签: javascript arrays

我有一个对象数组

[
{
    id1: {
        props1: 1,
        props2: 2,
        props3: 3
    }
},
{
    id2: {
        props1: 1,
        props2: 3,
        props3: 4
    }
},
{
    id3: {
        props1: 1,
        props2: 2,
        props3: 4
    }
},
{
    id4: {
        props1: 2,
        props2: 2,
        props3: 3
    }
},
{
    id5: {
        props1: 2,
        props2: 2,
        props3: 4
    }
}]

我想互相比较元素(对象),以获得包含相同的props1props2的所有两个对象

所以我的结果应该是

[
    [
        {
            id1: {
                props1: 1,
                props2: 2,
                props3: 3
            }
        },
        {
            id3: {
                props1: 1,
                props2: 2,
                props3: 4
            }
        }
    ],
    [
        {
            id4: {
                props1: 2,
                props2: 2,
                props3: 3
            }
        },
        {
            id5: {
                props1: 2,
                props2: 2,
                props3: 4
            }
        }
    ]
]

有没有办法在不使用2个for循环的情况下互相比较2个元素(对象)?当数组的大小很大时,我担心2 for循环解决方案的性能

2 个答案:

答案 0 :(得分:0)

您可以对列表进行分组,然后获得至少包含2个元素的分组。

Object.defineProperty(Array.prototype, "groupBy", {
  configurable: false,
  writable: false,
  value: function(expression) {
    return Array.prototype.reduce.call(this, function(result, value, index, array) {
      var key = expression.call(array, value, index, array);
      if (!(key in result)) result[key] = [];
      result[key].push(value);
      return result;
    }, {});
  }
});

var groups = [{
    props1: 1,
    props2: 2,
    props3: 3
  },
  {
    props1: 1,
    props2: 3,
    props3: 4
  },
  {
    props1: 1,
    props2: 2,
    props3: 4
  },
  {
    props1: 2,
    props2: 2,
    props3: 3
  }
].groupBy(x => `${x.props1}, ${x.props2}`);

console.log("All the groups: ");
console.log(groups);

console.log("Groups with at least 2 items: ");
console.log(Object.keys(groups).filter(key => groups[key].length > 1).map(key => groups[key]));

如果您绝对只想进行1次传递,则可以通过牺牲抽象来通过以下方式实现。

function groupArray(list, expression) {
  var tempList = {};
  return list.reduce(function(result, value, index, array) {
    var key = expression.call(array, value, index, array);
    if (!(key in tempList)) tempList[key] = [];
    else result[key] = tempList[key];
    tempList[key].push(value);
    return result;
  }, {});
}

var groups = groupArray([{
    props1: 1,
    props2: 2,
    props3: 3
  },
  {
    props1: 1,
    props2: 3,
    props3: 4
  },
  {
    props1: 1,
    props2: 2,
    props3: 4
  },
  {
    props1: 2,
    props2: 2,
    props3: 3
  }
], x => `${x.props1}, ${x.props2}`);

console.log("All the groups with at least 2 elements: ");
console.log(groups);

答案 1 :(得分:0)

无耻的自我插入:我的图书馆blinq对于有效执行这种转换非常方便。

const {
  blinq,
  deepComparer
} = window.blinq;
const data = [{
    id1: {
      props1: 1,
      props2: 2,
      props3: 3
    }
  },
  {
    id2: {
      props1: 1,
      props2: 3,
      props3: 4
    }
  },
  {
    id3: {
      props1: 1,
      props2: 2,
      props3: 4
    }
  },
  {
    id4: {
      props1: 2,
      props2: 2,
      props3: 3
    }
  },
  {
    id5: {
      props1: 2,
      props2: 2,
      props3: 4
    }
  }
]

const transformedData = blinq(data)
  .selectMany(x => Object.entries(x))
  .groupBy(([k, v]) => ({
    props1: v.props1,
    props2: v.props2
  }), deepComparer)
  .where(g => g.count() > 1)
  .select(g => g
    .select(x => Object.fromEntries([x]))
    .toArray()
  )
  .toArray();

console.log(transformedData);
<script src="https://cdn.jsdelivr.net/npm/blinq"></script>