在数组中添加或删除元素

7
我希望您能将一个对象添加到数组中,如果该对象不存在,则将其添加到数组中,如果它已经存在于数组中,则删除它。我成功地添加了第一项,但如果我在数组中添加另一个对象,则无法正常工作。我可以删除第一项。有一个错误,我不知道为什么。
以下是我的代码:
function checkAmi(pseudo, id) {
    var info = ({
        pseudo: pseudo,
        id: id
    });
    if (amisNotifies.length > 0) {
        // iterate over each element in the array
        for (var i = 0; i < amisNotifies.length; i++) {
            console.log(angular.toJson(amisNotifies[i].pseudo));
            // look for the entry with a matching `code` value
            if (amisNotifies[i].pseudo === pseudo) {
                amisNotifies.removeValue('pseudo', pseudo);
                $("#checkAmi" + id).addClass("fa-circle-o");
                $("#checkAmi" + id).removeClass("fa-check-circle-o");
            } else {
                amisNotifies.push(info);
                $("#checkAmi" + id).removeClass("fa-circle-o");
                $("#checkAmi" + id).addClass("fa-check-circle-o");
            }
        }
    } else {
        amisNotifies.push(info);
        $("#checkAmi" + id).removeClass("fa-circle-o");
        $("#checkAmi" + id).addClass("fa-check-circle-o");
    }
}

amisNotifies是什么?removeValue又是什么? - Tomalak
amisNotifies = []; removeValue 是一个函数,它可以删除对象值伪代码。 - DionysoSong
在标准的JS数组中没有名为removeValue的函数。 - Tomalak
我已经做到了,我说它在主题中有效,我成功添加了第一个并将其删除。 - DionysoSong
如果你寻求帮助但没有展示所有相关的代码,那么就无法提供帮助。 - Tomalak
你正在从0到length-1进行循环。如果你在索引i处删除一个项目,那么在重新进入循环时,位于i+1的项目将移动到位置i,因此会被跳过。你可以通过从length-1到0进行迭代来解决这个问题。 - Mike Samuel
7个回答

18

你可以做到这一点

const addOrRemove = (array, item) => {
  const exists = array.includes(item)

  if (exists) {
    return array.filter((c) => { return c !== item })
  } else {
    const result = array
    result.push(item)
    return result
  }
}

2
这个答案存在一个相当微妙的缺陷,具体取决于使用情况,可能是问题也可能不是问题。在正分支中,你返回了一个全新的数组。然而,在负分支中,你改变了现有的数组并返回它。最佳实践是选择一种策略并保持一致。如果你完全遵循函数式编程,那么你应该避免突变。 - J. Munson

11

测试过

这是另一个简单的解决方案:

var newItem = "NEW_ITEM_TO_ARRAY";
var array = ["OLD_ITEM_1", "OLD_ITEM_2"];
array.indexOf(newItem) === -1 ? array.push(newItem) : array.splice(array.indexOf(newItem), 1);

console.log(array)
如果未找到,则indexOf返回-1,这意味着如果它不存在,您将添加... 如果找到了,则会删除它并使用splice,其中第一个参数是索引,第二个参数是要删除的元素数:更多信息请参见: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

2

内置的popshift 方法可以分别从数组的两端删除元素。

如果你想要删除数组中间的一个元素,可以使用 splice 方法,方法如下:

function removeElementAtIndex(arr, i) {
  Array.prototype.splice.call(arr, i, 1);
}

如何确定一个元素是否在数组中取决于你对 "在 " 的理解。
`indexOf` 是相当好用的,但有一种特殊情况:`[NaN].indexOf(NaN)` 的结果是 `-1`,因为 `NaN !== NaN`。
假设你不担心 `NaN`,你可以这样做:
function togglePresent(arr, el) {
  var idx = arr.indexOf(el);
  if (idx >= 0) {
    arr.splice(idx, 1);
  } else {
    arr.push(el);
  }
}

如果你关心的话,当isNaN(el)时,你可以尝试不同的策略重新计算idx

注意:这仅会在arr中删除一个el实例。


但是我加了console.log来测试它,它一直运行到循环的push操作。它没有推送新信息。 - DionysoSong
@guillaumekotarba,你是如何记录它的?当你将一个对象传递给console.log而不是一个字符串时,它可能会延迟将其转换为字符串,这意味着日志消息可能不代表在调用console.log时的消息状态。 - Mike Samuel

1
你的逻辑似乎不正确——假设你在amiNotifies中有2个项目,你想添加第三个新值——第一次for循环运行(i=0)时,它会添加该项(伪造),第二次(i=1)它将删除已添加的项(伪造),最终新项将不会被添加,你应该重新设计基于amiNotifies中存在而添加和删除的逻辑。
你可能需要使用splice操作从amiNotifies中删除值。

1
你错误地检查了重复,只是通过与 pseudo 比较每个项目。你需要循环遍历所有项目,以查看是否匹配任何项目,然后根据匹配执行添加/删除操作。以下代码适用于您。
function checkAmi(pseudo, id) {
    var info = ({
        pseudo: pseudo,
        id: id
    });
    var getIndexOf = function (psdu) {
        for (var i = 0; i < amisNotifies.length; i++) {
            if (amisNotifies[i].pseudo === psdu) {
                return i;
            }
        }

        return -1;
    };

    if (amisNotifies.length > 0) {
        var index = getIndexOf(pseudo);
        if (index > -1) {
            //so already exists. now remove it.
            Array.prototype.splice.call(amisNotifies, index, 1);
            $("#checkAmi" + id).addClass("fa-circle-o");
            $("#checkAmi" + id).removeClass("fa-check-circle-o");
        }
        else {
            //does not exist, now add it
            amisNotifies.push(info);
            $("#checkAmi" + id).removeClass("fa-circle-o");
            $("#checkAmi" + id).addClass("fa-check-circle-o");
        }

    } else {
        amisNotifies.push(info);
        $("#checkAmi" + id).removeClass("fa-circle-o");
        $("#checkAmi" + id).addClass("fa-check-circle-o");
    }
}

0
在 vue-3 项目中,我做了这个:
<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const itemsSelected = ref([]);

    const addOrRemoveItem = (itemId) => {
      const exists = itemsSelected.value.includes(itemId);

      if (exists) {
        itemsSelected.value = itemsSelected.value.filter((id) => id !== itemId);
      } else {
        itemsSelected.value.push(itemId);
      }
    };

    return { addOrRemoveItem };
  },
});
</script>

0

这是我使用的。Typescript,但是去除类型提示以在JS中使用。

export function addOrRemove<T>(source: T[], candidate: T, comparator?: (a: T, b: T) => boolean): T[] {
  const c = comparator || ((a, b) => a == b)
  const e = source.find(i => c(i, candidate))
  return e ? source.filter(i => !c(i, candidate)) : [...source, candidate]
}

它将不可变地切换数组元素(如果存在则删除,如果不存在则添加)。最后一个参数可以使用可选的比较器函数来比较非标量值,例如对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接