Categories
Lodash

Plain JavaScript of Lodash Array Methods

Lodash is a very useful utility library that lets us work with objects and arrays easily.

However, now that the JavaScript standard library is catching up to libraries such as Lodash, we can implement many of the functions in simple ways.

In this article, we’ll look at how to implement a few Lodash methods with plain JavaScript.

dropRightWhile

The dropRightWhile function lets us create a slice of an array starting from the right until a condition is met. The condition is determined by a callback.

We can implement it as follows with plain JavaScript as follows:

const dropRightWhile = (arr, condition) => {
  const newArr = [];
  for (let i = arr.length - 1; i >= 0; i--) {
    if (condition(arr[i])) {
      return newArr;
    }
    newArr.push(arr[i]);
  }
  return newArr;
}

In the code above, we have a for loop that’s looped through in reverse. If the condition function, which takes an array entry as the value returns true , then we return newArr , which has the items that are pushed into the array that we want to keep.

If the loop finishes without returning newArr , then it’ll also return newArr .

Therefore, when we have:

const arr = [1, 2, 3]
const dropped = dropRightWhile(arr, (a) => a === 2)

We get that dropped is [3] since we stopped the function when the callback condition is met, which is when an array entry is 2.

dropRightWhile can also take a string with the key name to check if it’s true before returning the sliced array.

We can add that check easily with the following code:

const dropWhile = (arr, key) => {
  const newArr = [];
  for (let i = arr.length - 1; i >= 0; i--) {
    if (arr[i][key]) {
      return newArr;
    }
    newArr.push(arr[i]);
  }
  return newArr;
}

Then when we have the following array and call it as follows:

const arr = [{
    name: 'foo',
    active: false
  },
  {
    name: 'bar',
    active: true
  },
  {
    name: 'baz',
    active: false
  }
]
const dropped = dropRightWhile(arr, 'active');

We get:

[
  {
    "name": "foo",
    "active": false
  }
]

since we return the array where we push the entries from the right until active is true .

dropWhile

dropWhile is the opposite of dropRightWhile . It gets a slice of an array by starting from the beginning and pushing those items into a new array, and returning it either when the loop finishes or when the condition in the callback returns true .

Like dropRightWhile , the callback takes an array entry. For instance, we can implement it ourselves as follows:

const dropWhile = (arr, condition) => {
  const newArr = [];
  for (const a of arr) {
    if (condition(a)) {
      return newArr;
    }
    newArr.push(a);
  }
  return newArr;
}

In the code above, we used the for...of loop instead of a regular for loop since we’re just looping through arr forward, which can be done easily with for loop.

dropWhile can also take a string with the key name to check if it’s true before returning the sliced array.

We can add that check easily with the following code:

const dropWhile = (arr, key) => {
  const newArr = [];
  for (const a of arr) {
    if (a[key]) {
      return newArr;
    }
    newArr.push(a);
  }
  return newArr;
}

Then when we have the following array and call it as follows:

const arr = [{
    name: 'foo',
    active: false
  },
  {
    name: 'bar',
    active: true
  },
  {
    name: 'baz',
    active: false
  }
]
const dropped = dropWhile(arr, 'active');

We get:

[
  {
    "name": "foo",
    "active": false
  }
]

since we return the array where we push the entries until active is true .

fill

The fill method fills the element of an array with values from the start but not up to the end index by replacing the values from the original array with the one that we provide starting from a starting index and ending with the end index.

We can implement fill as follows:

const fill = (arr, value, start, end) => arr.fill(valu, start, end)

In the code above, we have 4 arguments like the Lodash’s fill method, which are arr for the original array, value which is the value we want to fill the array with. start , which is the starting index of array entry we’re replacing, and end , which is the end index of the array we’re replacing the values with.

Then when we call the fill as follows:

const filled = fill([1, 2, 3, 4, 5], 8, 0, 3);

We get that filled is:

[8, 8, 8, 4, 5]

As we can see, the array instance’s fill method does the same job as Lodash’s fill .

Conclusion

We can implement dropWhile , dropRightWhile , and fill easily with plain JavaScript’s array methods. With a few lines of code, we eliminated the need to use Lodash array methods.

Categories
Lodash

Plain JavaScript versions of Lodash Array Filtering and Manipulation Methods

Lodash is a very useful utility library that lets us work with objects and arrays easily.

However, now that the JavaScript standard library is catching up to libraries such as Lodash, we can implement many of the functions in simple ways.

We can implement the pullAllBy , pullAllWith , pullAt , and remove methods easily with plain JavaScript.

pullAllBy

The pullAllBy returns an array that removes the given values that matches the items we want to remove after converting them with the iteratee function.

We can implement it as follows:

const pullAllBy = (arr, values, iteratee) => arr.filter(a => !values.map(iteratee).includes(iteratee(a)))

In the code above, we call the given iteratee function to map the values before doing the comparison with includes . Also in includes , we also call iteratee to do the same conversion so that they can be compared properly.

Then we can use our pullAllBy function as follows:

const result = pullAllBy([1, 2.1, 3], [2.2, 3], Math.floor)

And we get [1] for result .

pullAllWith

The Lodash pullAllWith method takes a comparator instead of the iteratee to compare the values to exclude with the comparator instead of an iteratee to convert the values before comparing them.

For instance, we can implement it as follows:

const pullAllWith = (arr, values, comparator) => arr.filter(a => values.findIndex((v) => comparator(a, v)) === -1)

In the code above, we use the plain JavaScript’s findIndex method with a callback that calls the comparator to compare the values.

We call filter to filter out them items that are included with the values array.

Then when we call it as follows:

const result = pullAllWith([1, 2, 3], [2, 3], (a, b) => a === b)

We get [1] for result .

pullAt

The Lodash pullAt method returns an array with the elements with the items with the given indexes.

It also removes the elements in-place with those indexes.

Again, we can use the filter method to filter out the items that we want to remove as follows:

const pullAt = (arr, indexes) => {
  let removedArr = [];
  const originalLength = arr.length
  for (let i = 0; i < originalLength; i++) {
    if (indexes.includes(i)) {
      removedArr.push(arr[i]);
    }
  }

  for (let i = originalLength - 1; i >= 0; i--) {
    if (indexes.includes(i)) {
      arr.splice(i, 1);
    }
  }
  return removedArr.flat()
}

In the code above, we used a for loop to loop through the array and call splice on arr on the items with the given index in the indexes array.

Then we push the removed items into the removedArr array.

We then have and 2nd loop, which loops arr in reverse so that it doesn’t change arr ‘s indexes before we call splice on it.

In the loop, we just call splice to remove the items with the given index.

Finally, we call flat to flatten the array since splice returns an array.

Therefore, when we call it as follows:

const arr = [1, 2, 3]
const result = pullAt(arr, [1, 2])

We see that result is [2, 3] since we specified [1, 2] in the array with the index to remove and arr is now [1] since that’s the only one that’s not removed.

remove

The remove method removes the items from an array in place with the given condition and returns the removed items.

We can implement it ourselves with the for loop as follows:

const remove = (arr, predicate) => {
  let removedArr = [];
  const originalLength = arr.length
  for (let i = 0; i < originalLength; i++) {
    if (predicate(arr[i])) {
      removedArr.push(arr[i]);
    }
  }
  for (let i = originalLength - 1; i >= 0; i--) {
    if (predicate(arr[i])) {
      arr.splice(i, 1);
    }
  }
  return removedArr.flat();
}

In the code above, we have 2 loops as we have with the pullAt method. However, instead of checking for indexes, we’re checking for a predicate .

Like pullAt , we have to loop through the array indexes in reverse to avoid splice changing the indexes as we’re looping through the items of arr .

Then when we call remove as follows:

const arr = [1, 2, 3]
const result = remove(arr, a => a > 1)

We get that result is [2, 3] and arr is [1] since we specified that the predicate is a => a > 1 , so anything bigger than 1 is removed from the original array and the rest are returned.

Conclusion

The pullAt and remove methods are very similar, except that pullAt takes an array of index and remove takes a callback with the given condition.

pullAllBy and pullAllWith are implemented with the filter method. pullAllBy also needs to map the values with the iteratee function before doing comparisons.

Categories
Lodash

Learning JavaScript by Implementing Lodash Methods — Objects

Lodash is a very useful utility library that lets us work with objects and arrays easily.

However, now that the JavaScript standard library is catching up to libraries such as Lodash, we can implement many of the functions in simple ways.

In this article, we’ll look at some Lodash object methods that we can implement ourselves in plain JavaScript.

forInRight

The forInRight method loops through the own and inherited properties of an object in reverse order. In each iteration, it calls the iteratee function with the value, key, and object arguments until it returns false . Then the loop will end.

value is the value of the object property that’s being looped through. key is the key of the property that’s being looped through, and object is the object where the properties are being traversed.

We can implement that ourselves by using the for...in loop to get all the keys in the order that it returns and put them in an array.

Then we can reverse the keys by calling the array instance’s reverse method and use the for...of loop to loop through the keys:

const forInRight = (object, iteratee) => {
  const keys = [];
  for (const key in object) {
    keys.push(key);
  }
  const reversedKeys = keys.reverse();
  for (const key of reversedKeys) {
    const result = iteratee(object[key], key, object);
    if (result === false) {
      break;
    }
  }
}

In the code above, we first used the for...in loop to loop through the keys of an object forward and put them all in the keys array.

In the for...in loop, we push the keys into the keys array. Then we reverse the keys that are in keys array by calling reverse and then assign the reversed array as the value of reversedKeys .

Then we can use the for...of loop to loop through reversedKeys and then call iteratee with object[key], key, and object . We assigned the returned value of iteratee to result .

When result is false , we break the loop.

Now when we call it with the Foo constructor as follows:

function Foo() {
  this.a = 1;
  this.b = 2;
}

Foo.prototype.c = 3;

forInRight(new Foo(), (value, key) => console.log(key));

We get that we get back c , b and a as the logged values in that order.

findKey

The Lodash findKey finds the first property of an object where the predicate returns true .

We can implement that by traversing the items of an object and call the predicate function to check if the given property value matches the condition returned by the predicate .

For instance, we can implement that as follows:

const findKey = (object, predicate) => {
  for (const key of Object.keys(object)) {
    if (predicate(object[key])) {
      return key
    }
  }
}

In the code above, we used Object.keys to get the own keys of object . Then we looped through the keys with the for...of loop.

Inside the loop, we call predicate with the value of the object to see if it meets the condition defined in the preicate function.

Then when we run the findKey function as follows:

const users = {
  'foo': {
    'age': 15,
    'active': true
  },
  'bar': {
    'age': 30,
    'active': false
  },
  'baz': {
    'age': 1,
    'active': true
  }
};

const result = findKey(users, o => o.age < 40);

We have the users object with multiple keys with an object with the age and active properties as the value.

Then we called findKey with it and the predicate function set to o => o.age < 40 .

We then get that 'foo' is the value of result .

findLastKey

Lodash’s findLastKey function is like findKey except the keys are looped over in the opposite order of it.

To implement it, we can just change our findKey implement by calling the reverse method on the keys array returned by Object.keys .

We can do that as follows:

const findLastKey = (object, predicate) => {
  for (const key of Object.keys(object).reverse()) {
    if (predicate(object[key])) {
      return key
    }
  }
}

Then we call our findLastKey function as follows:

const users = {
  'foo': {
    'age': 15,
    'active': true
  },
  'bar': {
    'age': 30,
    'active': false
  },
  'baz': {
    'age': 1,
    'active': true
  }
};

const result = findLastKey(users, o => o.age < 40);

We get 'baz' as the value of result instead of 'foo' since we looped through the keys in reverse.

Conclusion

The forInRight method can be implemented by putting the own and inherited in an array by looping through them with the for...in loop and then pushing them in the array.

Then we can loop through them with the for...of loop and call the iteratee function on it.

The findKey and findKeyRight functions can be implemented by looping through the keys and then calling the predicate function on it.

Categories
Lodash

Learning JavaScript by Implementing Lodash Methods — Unzipping Arrays and Excluding Items

Lodash is a very useful utility library that lets us work with objects and arrays easily.

However, now that the JavaScript standard library is catching up to libraries such as Lodash, we can implement many of the functions in simple ways.

In this article, we’ll look at how to implement array methods for excluding items and unzipping arrays.

unzip

unzip accepts an array of grouped elements and creates an array by regrouping the elements into their configuration before zipping them.

All we have to do to implement unzip is to loop through each of the arrays and rearrange them as follows:

const unzip = (zipped) => {
  let unzipped = zipped[0].map(z => []);
  for (let j = 0; j < unzipped.length; j++) {
    for (let i = 0; i < zipped.length; i++) {
      unzipped[j].push(zipped[i][j])
    }
  }
  return unzipped;
}

In the code above, we created a function that takes zipped arrays and inside the function, we mapped the first entry of zipped to a new array of arrays.

This is because the unzipped array should have arrays that are of the same size as each array entry in the zipped array.

Then we push the zipped entry in the given position into the unzipped array’s array entry.

For instance, if we call unzip with the following zipped array:

const result = unzip([
  ['a', 1, true],
  ['b', 2, false]
]);

Then unzip first maps the first zipped entry into a new array and set it to the unzipped variable.

Then the nested loop takes 'a' and then puts it into the first entry of the unzipped array. Then it pushes 'b' as the 2nd entry of the same array.

In the next iteration, it pushes 1 into the next unzipped array entry. Then it pushes 2.

The same process is done for the next iteration. Therefore, the unzipped array should be:

[
  [
    "a",
    "b"
  ],
  [
    1,
    2
  ],
  [
    true,
    false
  ]
]

unzipWith

unzipWith is like unzip , but we can pass in an iteratee function to choose how to regroup our array. The iteratee function takes 2 arguments and returns the one that’s the combination of the 2.

For instance, we can implement unzipWith as follows:

const unzipWith = (zipped, iteratee) => {
  let unzipped = zipped[0].map(z => []);
  for (let j = 0; j < unzipped.length; j++) {
    for (let i = 0; i < zipped.length; i++) {
      unzipped[j].push(zipped[i][j])
    }
  }
  return unzipped.map(arr => {
    return arr.reduce(iteratee);
  });
}

It’s almost the same as unzip except that we called reduce to combine the values with iteratee via the map method before returning the unzipped array.

Then when we call it as follows:

const result = unzipWith([
  [1, 10, 100],
  [2, 20, 200]
], (a, b) => a + b);

We get:

[
  3,
  30,
  300
]

for result .

without

The Lodashwithout method returns an array that excludes all the given values using the SameValueZero algorithm for comparison.

We can easily exclude items with our own without function as follows:

const without = (arr, values) => arr.filter(a => !values.includes(a))

In the code above, we called filter on arr and the leave the ones that aren’t in values by calling includes to check if it’s in values .

Then when we call it as follows:

const result = without([1, 2, 3, 4, 5], [4]);

We get that result is:

[
  1,
  2,
  3,
  5
]

xor

The xor function returns an array of unique values that aren’t included in all arrays. This is also known as the symmetric difference.

The order of the result is determined by when they occur in the array.

To implement it, we can just check whether they occur in all arrays and then exclude them if they do:

const xor = (...arrs) => {
  const symDiff = [];
  for (const arr of arrs) {
    for (const a of arr) {
      const inAllArrays = arrs.every(arr => arr.includes(a));
      if (!inAllArrays) {
        symDiff.push(a);
      }
    }
  }
  return symDiff;
}

In the code above, we looped through each array in arrs then inside, we loop through each array entry in each entry of arrs and check whether an element is in every array in arrs by using the every method on arrs .

The callback uses includes to check whether each element is in each array in arrs .

If it’s not, then we push it to the symDiff array, and in the end, we return that array.

Then when we call it as follows:

const result = xor([2, 1], [2, 3])

We get that result is:

[
  1,
  3
]

since 1 and 3 are not in all the arrays.

Conclusion

unzipping arrays means that we’re rearranging the entries so that each entry in the nested array is now in their own array position.

We can also return a new array with some entries excluded with the without function, which we can implement with filter and includes .

Finally, we can find the symmetric difference by checking if the elements are included in each array in the nested array and exclude those.

Categories
Lodash

Learning JavaScript by Implementing Lodash Methods — Objects and Functions

Lodash is a very useful utility library that lets us work with objects and arrays easily.

However, now that the JavaScript standard library is catching up to libraries such as Lodash, we can implement many of the functions in simple ways.

In this article, we’ll look at some Lodash object and function methods that we can replace with our own plain JavaScript implementation.

unary

The Lodash unary method returns a function that only calls the original function with one argument.

We can just create our own function that returns a function that calls the original function ourselves as follows:

const unary = (fn) => (val) => fn(val);

In the code above, we have our own unary function, which takes a function that returns (val) => fn(val) , which is a function that only takes one argument and then calls fn with that argument.

Then we can call it as follows:

const result = ['6', '8', '10'].map(unary(parseInt));

And we get:

[
  6,
  8,
  10
]

as the value of result .

wrap

The Lodash wrap method takes a wrapper function another function fn that we want to call with the wrapper as the first argument.

It returns a function that takes in a value val as the parameter and calls the function in the second argument with the wrapper as the first argument and val as the 2nd argument.

For instance, we can implement our own wrap function as follows:

const wrap = (wrapper, fn) => (val) => fn(wrapper, val)

In the code above, the wrap function takes wrapper and fn , which are functions. Then we return a function that takes in an argument, which is val and then calls fn with wrapper and val .

Then we can call it as follows with the Lodash _.escape method as the first argument and our own function to wrap our text around p tags as follows:

const p = wrap(_.escape, (func, text) => `<p>${func(text)}</p>`);

In the code above, the escape method escapes the text and our own function wraps func(text) , where func is the escape method since that’s the first argument and text is the text that we’ll pass into the returned p function.

Then we can call p as follows:

const result = p('foo bar');

and we get that result is <p>foo bar</p> .

forIn

The Lodash forIn method loops through the own and inherited enumerable string keyed properties of an object and run an iteratee function on each property.

The iteratee is a function that takes the value , key , and object parameters and we can stop the loop by returning false explicitly

We can implement our own forIn function as follows:

const forIn = (object, iteratee) => {
  for (const key in object) {
    const result = iteratee(object[key], key, object);
    if (result === false) {
      break;
    }
  }
}

In the code above, we have the forIn function that takes an object and an iteratee function.

Then inside the function, we used the for...in loop to loop through all the enumerable own and enumerable string keys of object .

Inside the loop, we call the iteratee function with the value, which we get by using object[key] , the key itself, and the object . We assign the return value of iteratee to result .

Then if result is false , then we break the loop. Otherwise, it continues running.

We can then call our forIn function as follows:

function Foo() {
  this.a = 1;
  this.b = 2;
}

Foo.prototype.c = 3;

forIn(new Foo(), (value, key) => console.log(key));

In the code above, we have the Foo constructor, which has 2 own properties a and b . It also has an additional inherited property c .

Then we called forIn with a Foo instance, and pass in a callback that logs the keys of the Foo instance.

In the end, we should see a , b and c logged in the console log output.

Conclusion

The unary and wrap Lodash methods both return a function that takes in some arguments and call the original function that’s passed in as the argument from the returned function.

Lodash’s forIn method is like the for...in loop, except that we can return false with our iteratee function to break the loop. The iteratee is run on every iteration until it returns false .