Сравнение массивов массивов с Lodash - PullRequest
0 голосов
/ 24 марта 2019

Я не могу понять, как вытащить массивы из одного массива из другого.

Я пытался использовать простой JavaScript (ES6):

let openTiles = [[1, 1], [2, 2], [1, 3]]
let usedTiles = [[1, 1], [2, 2]]
openTiles = openTiles.filter((item) => !usedTiles.includes(item))

Я ожидал, что финальные openTiles будут: [[1, 3]], но они не изменились. Проблема в том, что приведенный выше код использует стандартное сравнение JavaScript (===), которое не может сравнивать один массив с другим. В Lodash есть функция _.isEqual (), но я не могу понять, как это реализовать.

Я пытался:

openTiles = openTiles.filter((item) => {
    return usedTiles.every((el) => {
        _.isEqual(item, el)
    })
})

но это дает мне пустой массив. Я хотел бы посмотреть, как люди включают функцию Lodash _.isEqual (), чтобы все массивы в usedTiles могли быть удалены из openTiles.

Ответы [ 3 ]

3 голосов
/ 24 марта 2019

Вместо того, чтобы пытаться написать универсальную функцию, равную объекту или массиву, или использовать функции из lodash, Ramda, underscore и т. Д., Вы можете написать одну для вашего типа. Если ваши плитки - это просто двухэлементные массивы, просто напишите функцию equals, которая отражает это. Тогда вы можете использовать его в some:

const tilesEqual = (a) => (b) => a[0] == b[0] && a[1] == b[1]
const removeTiles = (open, used) => open.filter(
  tile => !used.some(tilesEqual(tile))
)

let openTiles = [[1, 1], [2, 2], [1, 3]]
let usedTiles = [[1, 1], [2, 2]]

console.log(removeTiles(openTiles, usedTiles))

Относительно того, почему ваш код выше не работал, есть две проблемы. Вы не хотите знать, соответствует ли every использованная плитка вашей текущей. Вы только хотите знать, some из них делают. Тогда, поскольку это те, которые вы хотите удалить, вы должны отрицать это для filter. Итак, вы хотите что-то вроде !usedTiles.some(...).

Но есть и другая проблема. Вы ничего не возвращаете в обратном вызове на every / some:

    return usedTiles.every((el) => {
        _.isEqual(item, el)
    })

Вам нужно переключить это либо на

    return usedTiles.every((el) => _.isEqual(item, el))

или

    return usedTiles.every((el) => {
        return _.isEqual(item, el)
    })

Это простая ошибка, и она довольно распространена. Если вы используете функцию со стрелкой с блоком с разделителями { - }, вам нужен оператор return.

3 голосов
/ 24 марта 2019

Простой метод состоит в том, чтобы упорядочить массивы, с которыми вы хотите сравнить, чтобы .includes работал правильно:

let openTiles = [[1, 1], [2, 2], [1, 3]]
let usedTiles = [[1, 1], [2, 2]]
const usedTilesStringified = usedTiles.map(JSON.stringify);
openTiles = openTiles.filter((item) => !usedTilesStringified.includes(JSON.stringify(item)))
console.log(openTiles);

Или вы можете явно сравнить каждое значение:

let openTiles = [[1, 1], [2, 2], [1, 3]];
let usedTiles = [[1, 1], [2, 2]];
openTiles = openTiles.filter((item) => {
  const { length } = usedTiles;
  outer:
  for (let i = 0, { length } = usedTiles; i < length; i++) {
    const usedTile = usedTiles[i];
    if (usedTile.length !== item.length) {
      continue;
    }
    for (let j = 0, { length } = usedTile; j < length; j++) {
      if (usedTile[j] !== item[j]) {
        // The current subarrays being compared are not identical:
        continue outer;
      }
    }
    // We've iterated through all indicies while comparing one subarray to another
    // they all match, so the arrays are the same, so this filter fails:
    return false;
  }
  return true;
})
console.log(openTiles);

Для менее общего решения, которое просто проверяет, равен ли индекс 0 индексу 1:

let openTiles = [[1, 1], [2, 2], [1, 3]];
let usedTiles = [[1, 1], [2, 2]];
openTiles = openTiles.filter((item) => {
  for (let i = 0, { length } = usedTiles; i < length; i++) {
    const usedTile = usedTiles[i];
    if (usedTile[0] === item[0] && usedTile[1] === item[1]) {
      return false;
    }
  }
  return true;
})
console.log(openTiles);
1 голос
/ 24 марта 2019

Чтобы вычесть один массив из другого lodash содержит ряд разностных методов.

Поскольку значение в вашем случае является массивом, простое равенство не сработает, потому что [] !== []. _.isEqual() Лодаша выполняет глубокое сравнение между двумя значениями.

Для комбинирования вычитания разности с проверкой _.isEqual() используйте _.differenceWith().

let openTiles = [[1, 1], [2, 2], [1, 3]]
let usedTiles = [[1, 1], [2, 2]]
openTiles = _.differenceWith(openTiles, usedTiles, _.isEqual)

console.log(openTiles)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
...