16

I am looking to store a list of unique string (hence Set) and wanted to retrieve the value based on the index. I used get(index) But it turned out it returns undefined. So it seems I did not understand Set well.

In case value needed to be retrieved do we have to convert it back to the array and then only read it or with "get(index)" it can be achieved?

Also, I have checked Set tests to understand get(index) but still not clear.

const { Set } = require('immutable');

const set = Set(["ab", "cd", "ef"])
console.log(set.get(1)) //logs undefined
console.log(set.toJS()[1]) //logs "cd"
Anil Namde
  • 6,452
  • 11
  • 63
  • 100
  • 1
    First you need to clarify for yourself if you are using ES6 `Set`, or Immutable.js `Set` - they are different. For one thing, the former doesn't have `get`. And Immutable.js provides `get` for all collections, but with sets it just returns the item itself: `new Immutable.Set().add("foo").get("foo")` returns `"foo"` (and `new Immutable.Set().add("foo").get("bar")` returns `undefined`). Sets are inherently unordered, "set index" makes no sense. If you want indices, you want an array (or at least `Immutable.IndexedSeq`). – Amadan Jun 23 '17 at 07:48
  • @Amadan thanks for the input, Set's Item is not strict ordered made me use List() and it looks promising. It seems I just scratched surface of Immutable :) – Anil Namde Jun 23 '17 at 14:42

7 Answers7

14

Another way to do that would be to use Array.from(set)[0].

user1514042
  • 1,899
  • 7
  • 31
  • 57
2

Here I'm trying to using the Set in es2015 directly without ImmutableJS:

You could write customized function like this:

Set.prototype.getByIndex = function(index) { return [...this][index]; }

var set = new Set(['a', 'b', 'c'])

console.log(set.getByIndex(0))  // 'a'

Note that the spread operator converts a set to an array so that you can use index to get access to the element

Chang
  • 1,658
  • 1
  • 17
  • 23
  • 2
    It is bad practice to modify objects that one does not own; this paradigm has already caused problems when [MooTools created their own Array.prototype.flatten](https://developers.google.com/web/updates/2018/03/smooshgate). – Alexander Turinske Jul 15 '20 at 22:25
  • [Here](https://humanwhocodes.com/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/) is another good article on the matter. It really makes code less maintainable when you modify objects you don't own. – jens1101 Apr 23 '21 at 14:01
2
let data = new Set();
data.add('Value 1');
data.add('Value 2');
data.add('Value 3');

function getSetValueByIndex(setObj, index) {
    return [...setObj][index]
}
console.log(getSetValueByIndex(data, 1))
1

the way to use Immutable's get is by "key" not by index

console.log(set.get("cd")) // logs cd, at index 1

if you want to get an element from the Set's iterator, you have to extend Immutable's Set

Set.prototype.getByIdx = function(idx){
  if(typeof idx !== 'number') throw new TypeError(`Argument idx must be a Number. Got [${idx}]`);

  let i = 0;
  for( let iter = this.keys(), curs = iter.next(); !curs.done; curs = iter.next(), i++ )
    if(idx === i) return curs.value;

  throw new RangeError(`Index [${idx}] is out of range [0-${i-1}]`);
}

const set = Set(["ab", "cd", "ef"]);

console.log(set.getByIdx(1)) //logs cd
theRemix
  • 2,154
  • 16
  • 16
1

Using Array.from() or spread requires iterating the entire set before returning an example. This is not ideal from a performance perspective.

A better solution would be:

function getSetValueByIndex(target, index) { 
  if (typeof index !== 'number') throw new Error(`Index must be a number!`);

  let i = 0;
  for (const item of target) if (i++ === index) return item;

  throw new Error(`Index ${index} out of bounds!`);
}
Ron S.
  • 563
  • 5
  • 13
0

Here's an improved version of @Ron S. 's answer. Works with negative indexes, just like Array.at

Set.prototype.at = function(index) {
    if (Math.abs(index) > this.size){
        return null;
    }

    let idx = index;
    if (idx < 0){
        idx = this.size + index;
    }
    let counter = 0;
    for (const elem of this){
        if (counter == idx){
            return elem
        }
        counter += 1;
    }
}
Mr.Kleiner
  • 15
  • 1
  • 5
-2

I find myself using an Array with another Set to check if I should put the new Value into the Array

example:

let myArray = [1,2,3,4]
let check = new Set(myArray)

function PushToArray( newValue ){
  if( !check.has(newValue) )
   myArray.push(newValue)
   check.add(newValue)
}

pery mimon
  • 7,713
  • 6
  • 52
  • 57