最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - All pairs in an ES6 Map - Stack Overflow

programmeradmin0浏览0评论

In ES6, given a Map, how would one visit pairs of values, where order is unimportant?

If this were arrays, I would do as follows:

let arr = ["a", "b", "c", "d"];

for (let i=0; i < arr.length; i++)
  for (let j=i+1; j<arr.length; j++)
    console.log(`${arr[i]},${arr[j]}`);

With Maps, I'm struggling to find a way to do something similar in an efficient and elegant manner. Iterators looked like they would do the trick, but I was assuming they would behave like C++ Standard Library iterators, where an iterator can be cloned into independent iterators.

The best I've e up with is:

var map = new Map([[0, "a"],[1, "b"],[2, "c"],[3, "d"]]);

for (let key of map.keys()) {
  let log_away = false;

  for (let other_key of map.keys()) {
    if (log_away)
        console.log(`${map.get(key)},${map.get(other_key)}`);
    else
        log_away = (key === other_key);
}

This is reasonably succinct, but having to visit all pairs, whether they will be used or not, is hardly efficient. Worse, if one were to try to adapt this to a Set containing large objects, the parison of keys at the end would have to be a parison of values, which could be prohibitively expensive.

In ES6, given a Map, how would one visit pairs of values, where order is unimportant?

If this were arrays, I would do as follows:

let arr = ["a", "b", "c", "d"];

for (let i=0; i < arr.length; i++)
  for (let j=i+1; j<arr.length; j++)
    console.log(`${arr[i]},${arr[j]}`);

With Maps, I'm struggling to find a way to do something similar in an efficient and elegant manner. Iterators looked like they would do the trick, but I was assuming they would behave like C++ Standard Library iterators, where an iterator can be cloned into independent iterators.

The best I've e up with is:

var map = new Map([[0, "a"],[1, "b"],[2, "c"],[3, "d"]]);

for (let key of map.keys()) {
  let log_away = false;

  for (let other_key of map.keys()) {
    if (log_away)
        console.log(`${map.get(key)},${map.get(other_key)}`);
    else
        log_away = (key === other_key);
}

This is reasonably succinct, but having to visit all pairs, whether they will be used or not, is hardly efficient. Worse, if one were to try to adapt this to a Set containing large objects, the parison of keys at the end would have to be a parison of values, which could be prohibitively expensive.

Share Improve this question edited Oct 15, 2016 at 21:10 Michał Perłakowski 92.9k30 gold badges163 silver badges188 bronze badges asked Oct 15, 2016 at 20:59 MarkMark 434 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 6

You can call the values() method and then call Array.from() on the result to get an array of all the values. Then you can do it as you do with arrays.

const map = new Map([[0, "a"],[1, "b"],[2, "c"],[3, "d"]])

const values = Array.from(map.values())
for (let i = 0; i < values.length; i++)
  for (let j = i + 1; j < values.length; j++)
    console.log(`${values[i]},${values[j]}`)

To add one more loop option to the mix (not better, just an alternative): using the rest operator to always loop through the remaining entries.

let map = new Map([[0, "a"],[1, "b"],[2, "c"],[3, "d"]]);

let arr = [...map.values()] ,v;
while(arr.length > 1){
  [v,...arr] =arr;  
  arr.forEach(v2 => console.log([v,v2].join(',')));
}

or do the same in a recursive function (variable) to get an array of pairs:

let map = new Map([[0, "a"],[1, "b"],[2, "c"],[3, "d"]]);

const fn = ([v,...a]) => v ? [...a.map(v2=>[v,v2].join()),...fn(a)] : [];
console.log(fn(map.values()));

You could bine the use of Array.from, map.values() and some to create this ES6 solution:

var map = new Map([[0, "a"],[1, "b"],[2, "c"],[3, "d"]]);

Array.from(map.values()).forEach( ([key1], i, a) =>
    a.some( ([key2], j) => i !== j ? console.log(key2, key1) : true )
);

This uses the fact that console.log does not return a value, so care has to be taken to reuse this in a more practical application. It might therefore be more useful to gather the pairs in an array, which can then be used for processing later:

NB: Use of the spread operator is of course an alternative for Array.from:

var map = new Map([[0, "a"],[1, "b"],[2, "c"],[3, "d"]]);

var pairs = [...map.values()].reduce( (acc, [key1], i, a) =>
    (a.some( ([key2], j) => i === j || !acc.push([key2, key1]) ), acc), []
);
console.log(pairs);

发布评论

评论列表(0)

  1. 暂无评论