Замена цикла for на цикл foreach

Я работаю над методами StateService, которые перемещают карточку задачи в следующий столбец. Мне удалось написать метод taskMoveLeft, который работает нормально, но я не могу дублировать его функциональность для метода taskMoveRight с помощью цикла forEach, я мог заставить его работать только с циклом for.

Рабочий пример метода taskMoveLeft (с использованием forEach):

taskMoveLeft(id) {
  state.columns.forEach((column, columnIndex) => {
    if (state.columns[0] !== column) {
      if (column.cards) {
        column.cards.forEach((card, cardIndex) => {
          if (card.id === id) {
            if (state.columns[columnIndex - 1].cards) {
              // Add card to the target column card collection
              state.columns[columnIndex - 1].cards.push(card);
            } else {
              // Create target column card collection and add card
              state.columns[columnIndex - 1].cards = Array.of();
              state.columns[columnIndex - 1].cards.push(card);
            }
            // Remove the card from the source column card collecion
            state.columns[columnIndex].cards.splice(cardIndex, 1);
          }
        });
      }
    }
  });
}

Рабочий пример метода taskMoveRight (с использованием цикла for):

taskMoveRight(id) {
  for (let i = 0; i < state.columns.length; i++) {
    if (state.columns[state.columns.length - 1] !== state.columns[i]) {
      if (state.columns[i].cards) {
        for (let j = 0; j < state.columns[i].cards.length; j++) {
          if (state.columns[i].cards[j].id === id) {
            if (state.columns[i + 1].cards) {
              // Add card to the target column card collection
              state.columns[i + 1].cards.push(state.columns[i].cards[j]);
            } else {
              // Create target column card collection and add card
              state.columns[i + 1].cards = Array.of();
              state.columns[i + 1].cards.push(state.columns[i].cards[j]);
            }
            // Remove the card from the source column card collecion
            return state.columns[i].cards.splice(j, 1);
          }
        }
      }
    }
  }
}

Не удается заставить метод taskMoveRight работать с петлей forEach. С этим кодом карта всегда перемещается в крайний правый столбец:

taskMoveRight(id) {
  state.columns.forEach((column, columnIndex) => {
    if (state.columns[state.columns.length - 1] !== column) {
      if (column.cards) {
        column.cards.forEach((card, cardIndex) => {
          if (card.id === id) {
            // Create target column card collection
            if (!state.columns[columnIndex + 1].cards) {
              state.columns[columnIndex + 1].cards = Array.of();
            }
            // Add card to the target column card collection
            state.columns[columnIndex + 1].cards.push(card);
            // Remove the card from the source column card collecion
            state.columns[columnIndex].cards.splice(cardIndex, 1);
          }
        });
      }
    }
  });
}

Почему вы А) Инвертировали условие if и Б) Удалили else?

T.J. Crowder 31.10.2018 11:46

Также обратите внимание, что цикл for, который вы пытаетесь заменить, в некоторых случаях заканчивается рано. Вы не можете преждевременно прервать последовательность forEach. Если вам нужно преждевременно прервать работу устройства, подобного forEach, используйте вместо него some (или every) или, возможно, в данном случае find.

T.J. Crowder 31.10.2018 11:47

Или, собственно, findIndex.

T.J. Crowder 31.10.2018 11:52

Боковое примечание: Array.of(); - очень странный способ записи []. :-)

T.J. Crowder 31.10.2018 11:55

> Почему вы: A) перевернули условие if и B) удалили else? Я перевернул его, потому что кода меньше, а логика осталась прежней.

Bong2000 31.10.2018 12:03
2
5
162
2

Ответы 2

forEach здесь не тот инструмент, потому что вы завершаете цикл раньше времени. Вместо этого, поскольку вам нужен индекс карты, используйте findIndex. См. Комментарии *** для этого и другие предложения:

taskMoveRight(id) {
  for (let i = 0; i < state.columns.length; i++) {
    // *** Instead of repeating it all over
    const column = state.columns[i];
    if (state.columns[state.columns.length - 1] !== column) {
      if (column.cards) {
        // *** Find the card
        const cardIndex = column.cards.findIndex(card => card.id == id);
        // *** Get the card if found
        const card = cardIndex !== -1 && column.cards[cardIndex];
        if (card) {
            // *** Instead of repeating it
            const nextColumn = state.columns[i + 1];
            if (nextColumn.cards) {
              // Add card to the target column card collection
              nextColumn.cards.push(card);
            } else {
              // Create target column card collection and add card
              // *** Using Array.of() to create an empty array and then pushing
              // *** to it is quite round-about; instead: [card]
              nextColumn.cards = [card];
            }
            // Remove the card from the source column card collecion
            return column.cards.splice(cardIndex, 1);
        }
      }
    }
  }
}

хорошо, если он работает для taskMoveLeft (), это, вероятно, правильный инструмент для этого

Jake11 31.10.2018 12:00

Да, с taskMoveLeft работает нормально, вопрос в том, как реверсировать направление и использовать для taskMoveRight

Bong2000 31.10.2018 12:02

Пожалуйста, помогите мне реализовать это методом forEach

Bong2000 31.10.2018 12:05

@ Jake11 - Нет, если вы посмотрите на taskMoveLeft, вы увидите, что он продолжает зацикливаться, хотя этого не должно быть - он уже нашел карту. Не тот инструмент.

T.J. Crowder 31.10.2018 12:12

@ Bong2000 - Почему вы хотите продолжать использовать неправильный инструмент для работы? Вышеупомянутое должно переместить столбец вправо, если это было в предыдущей реализации. Если нет, обновите свой вопрос, добавив в свой вопрос минимальный воспроизводимый пример, демонстрирующий действующий код, чтобы решения можно было протестировать против него.

T.J. Crowder 31.10.2018 12:14

@ T.J.Crowder Скорее всего, вы правы, что это неправильный инструмент, но сейчас меня больше интересует вопрос, почему я не могу продублировать тот же логин из moveTaskLeft. Буду очень признателен, если вы покажете мне, как это будет выглядеть с циклом forEach. Спасибо, что указали на правильный инструмент!

Bong2000 31.10.2018 12:19

Потому что вы изменяете следующую строку с текущими картами, а затем эти карты снова перемещаются, когда вы достигаете следующей строки. Вам нужно выполнить итерацию в обратном порядке, поэтому вместо .forEach((entry, i) вам нужно сделать:

  array.reverse().forEach((entry, i) => {
    i = array.length - 1 - i;

но это немного некрасиво.


Вместо этого я бы предпочел не .forEach, а цикл for. Я бы сохранил массив записей, чтобы перемещаться вправо, чтобы вы могли сократить логику до:

  let previousMove = [];

  for(const column of state.columns) {
    if(!column.cards) column.cards = [];
    let currentMove = column.cards.filter(card => card.id === id);
    column.cards = column.cards.filter(card => card.id !== id).concat(previousMove);
    previousMove = currentMove;
  }

Это также можно сделать с помощью reduce:

 state.columns.reduce((move, column) => {
    if(!column.cards) column.cards = [];
    const nextMove= coumn.cards.filter(card => card.id === id);
   column.cards = column.cards.filter(card => card.id !== id).concat(move);
   return nextMove;
 }, []);

Чтобы moveLeft, просто используйте reduceRight вместо reduce.

Другие вопросы по теме