0

I've been playing with the new ES6 Map(), just to get used to it, and, now we can get the size, it occurred to me that one could efficiently take random samples of a map, to see what it looked like.

Clearly it is possible to iterate through, make an Array of all entries, and then choose random samples. But this is unattractive for large maps.

There is some code at the end which achieves this by exploiting the newly-available size of the map. It is slightly more efficient than copying, but still unattractive.

But the Map method keys() returns an iterator object, whose next() method we normally use to iterate over a Map instance. And, it also includes an array of all the entries. This is shown in the following summary of the Chrome Devtools output:

coinNames.keys()
MapIterator
"keys"
....
[[Entries]]
:
Array[7]
0
:
30
1
:
12

... (entries omitted)

length
:
7

I could not find out how to access this array, so as to locate an entry by the array index.

The (rather pointless, but illustrative) code below works (given get_random_integer() and report()...).

The function play() is invoked on a button press, and logs a random name.

But, it would be nice not to iterate, and just get the entry at a given position in the array.

Any ideas?

function CoinName(name, slang, plural) {
    this.name = name;
    this.plural = plural;
}
const coinNames = new Map();

window.onload = init;
function init() {
    report ('OK');
    var button = document.getElementById('buttonA');
    button.addEventListener('click', play);

    coinNames.set(30, new CoinName('half crown'));
    coinNames.set(12, new CoinName('shilling', 'bob'));
    coinNames.set(3, new CoinName('threepenny bit'));
    coinNames.set(6, new CoinName('sixpence', 'tanner'));
    coinNames.set(1, new CoinName('penny', '', 'pence'));
    coinNames.set(1/4, new CoinName('farthing'));
    coinNames.set(1/2, new CoinName('halfpenny', 'hapeny',
                            'halfpence'));
}

function getRandomKey() {
    let requiredIndex = get_random_integer(0, coinNames.size);

    let keys = coinNames.keys();
    let found = undefined;
    let goon = true;
    let i = 0;
    while(goon) {
        goon = keys.next().value;
        //report(goon);
        if(goon && i===requiredIndex) {
            found = goon;
            goon = false;
        }
        i += 1;      
    }
    return found;
}

function play() {
    let key = getRandomKey();
    let entry = coinNames.get(key);
    report(entry.name);
}
John White
  • 131
  • 1
  • 3
  • 19

4 Answers4

1

If I understand your question correctly, you just want to get a random key from a Map object.

The simplest way that I can think of to accomplish this is to cast the iterator object returned by Map#keys to an array (using either the spread operator ..., or Array.from), then simply access a random index

const map = [['a','1'],['b','2'],['c','3']].reduce((m, e) => m.set(...e), new Map());
const getRandKey = map => [...map.keys()][Math.floor(Math.random() * 1000) % map.size];
let i = 10; while(i-- > 0) console.log(getRandKey(map));
1

You can use spread element to convert Map to Array, Array.prototype.entries() to get array of key, value pairs.

const map = new Map;

map.set(2, {abc:123});
map.set(7, {def:456});
map.set(1, {ghi:789});

let entries = [...map];
let len = entries.length;
let key = Math.floor(Math.random() * len);
let [prop, value] = entries[key];

console.log(prop, value);
guest271314
  • 1
  • 15
  • 104
  • 177
0

[[Entries]] is an inaccessible internal slot of the iterator. It's an implementation detail, not even specified by the language standard. You can't get at it.

Community
  • 1
  • 1
user2357112
  • 260,549
  • 28
  • 431
  • 505
-2

I agree with the comments above that it would be helpful if you could provide more context. That being said if you would like to iterate through the keys of an object, you need an array. To create an array of keys you can use Object.keys() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

const america = {
  California: "Sacramento",
  NewYork: "New York",
  Texas: "Austin"
}

const capitals = (america) => {
  let result = []
  for (var key in america) {
    result.push(america[key])
  }
  return result;
}
console.log(capitals(america))

const states = Object.keys(america)
console.log(states);