TypeOfNaN

Random JavaScript Tips

Nick Scialli
November 16, 2019

Introduction

Sometimes I find clever, interesting, or overlooked ways to solve certain problems in JavaScript. This is a first attempt to capture some of those items, randomly, in no particular order. I’m going to attempt to phrase these ideas as stackoverflow-esque questions/answers as we’re often googling the question we are trying to solve in the moment!

How do I keep only the items in one array that are also in another array?

Onemight be tempted to use the Array includes method for this solution, but that would be pretty inefficient:

const arr1 = [1, 2, 3, 2, 4, 5, 6];
const arr2 = [2, 4, 6];
const filtered = arr1.filter((el) => arr2.includes(el));

The big efficiency problem here is that it’s a loop inside a loop (filter loops through arr1 and includes loops through arr2 for each element of arr1). For a more efficient solution, consider using a Set to achieve hash table efficiency:

const arr1 = [1, 2, 3, 2, 4, 5, 6];
const arr2 = [2, 4, 6];
const arr2Set = new Set(arr2);
const filtered = arr1.filter((el) => arr2Set.has(el));

Now, you iterate through arr1 once (with filter) and arr2 once (when creating your Set). Note that, in this case, creating a new Set is only more efficient than using includes when the arrays get in the ~100 element range. If you’re optimizing for performance, be sure to do performance testing with your anticipated array sizes!

How do I flip keys and values in an object?

I have seen this accomplished using a combination of Object.entries and Array reduce, but I think a simple for...in loop is the most efficient way to accomplish this task

const myObj = {
  a: 'aKey',
  b: 'bKey',
  c: 'cKey',
};

const reversed = {};
for (key in myObj) {
  reversed[myObj[key]] = key;
}

How do I generate a random integer in a range, but exclude a subset of integers?

To accomplish this task, let’s create a function that takes the starting integer, ending integer, and an array of integers to exclude. For efficiency, we create an excludeLookup using a Set. We then do a for loop from the min to max value, only adding items to a nums array when they’re not in our excludeLookup set. Finally, we generate a random number by selecting a random element in our nums array!

function randomInt(min, max, exclude) {
  const nums = [];
  const excludeLookup = new Set(exclude);
  for (let i = min; i <= max; i++) {
    if (!excludeLookup.has(i)) nums.push(i);
  }
  if (nums.length === 0) return false;

  const randomIndex = Math.floor(Math.random() * nums.length);
  return nums[randomIndex];
}

console.log(randomInt(1, 5, [2, 3]));

How can I safety access child properties of an object when I don’t know if a parent object exists?

While we’re still waiting for optional chaining to be implemented widely, we can implement a safelyGet function that will let us either access deep object props or specify a safe fallback.

function safelyGet(obj, path, fallback = undefined) {
  let needle = obj;
  const found = path.every((el) => {
    if (needle[el] === undefined) return false;
    needle = needle[el];
    return true;
  });
  return found ? needle : fallback;
}

// Usage
const myObj = {
  user: {
    bio: {
      age: 25,
    },
  },
};

const age = safelyGet(myObj, ['user', 'bio', 'age']);
console.log(age); // 25

const permissions = safelyGet(myObj, ['user', 'auth', 'permissions'], 'none');
console.log(permissions); // "none"

How do I filter a list of items by an arbitrary starting string?

Perhaps you have a list of cities that you want to filter by a certain search string, but you only want to match the begging of the list of cities. To accomplish this, you can use indexOf and filter!

const cities = [
  'Barcelona',
  'Berlin',
  'Bucharest',
  'Budapest',
  'Dublin',
  'Lisbon',
];
const search = 'bu';
const filtered = cities.filter(
  (city) => city.toLowerCase().indexOf(search.toLowerCase()) === 0
);
console.log(filtered); // ["Bucharest", "Budapest"];

How can I truly shuffle an array?

The best method I’ve found for shuffling an array is to iterate through each element in the array and chose another element at random from the array to swap with it. This method is detailed on javascript.info here and is shown below. Note that this particular implementation creates a new array rather than modifying the input array.

function shuffle(oldArray) {
  const array = [...oldArray];
  for (let i = array.length - 1; i > 0; i--) {
    let j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

Conclusion

Okay, that’s enough for now. Stay tuned for part 2 at some point… maybe!

If you'd like to support this blog by buying me a coffee I'd really appreciate it!

Nick Scialli

Nick Scialli is a senior UI engineer at Microsoft.

© 2024 Nick Scialli