vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3数组去重

Vue3中对数组去重的方法总结

作者:BillKu

随着开发语言及人工智能工具的普及,使得越来越多的人会主动学习使用一些开发工具,本文主要介绍了Vue数组去重的几种方法,结合 Vue 3 的响应式特性实现数据更新,需要的朋友可以参考下

在 Vue 3 中对数组去重,本质上是 JavaScript 数组操作问题。以下是几种常用方法,结合 Vue 3 的响应式特性实现数据更新:

Vue 3数组去重方法

方法 1:使用 Set(推荐)

import { ref } from 'vue';

const list = ref([1, 2, 2, 3, 3, 3]);

// 去重逻辑
const deduplicate = () => {
  list.value = [...new Set(list.value)];
  
  // 或使用 Array.from
  // list.value = Array.from(new Set(list.value));
};

方法 2:使用 filter

const deduplicate = () => {
  list.value = list.value.filter(
    (item, index) => list.value.indexOf(item) === index
  );
};

方法 3:使用 reduce

const deduplicate = () => {
  list.value = list.value.reduce(
    (unique, item) => unique.includes(item) ? unique : [...unique, item],
    []
  );
};

完整组件示例

<template>
  <div>
    <button @click="deduplicate">去重</button>
    <ul>
      <li v-for="(item, index) in list" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const list = ref(['apple', 'banana', 'apple', 'orange', 'banana']);

const deduplicate = () => {
  // 任选一种去重方法
  list.value = [...new Set(list.value)];
};
</script>

对象数组去重(根据特定属性)

const users = ref([
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 1, name: 'Alice' } // 重复项
]);

const deduplicateObjects = () => {
  const seen = new Map();
  users.value = users.value.filter(item => {
    return !seen.has(item.id) && seen.set(item.id, true);
  });
};

注意事项:

  1. 响应式更新:直接赋值新数组 (list.value = [...]) 才能触发视图更新
  2. 性能考虑:大数组推荐使用 Set 或 Map,时间复杂度 O(n)
  3. 对象数组:需根据唯一标识(如 id)去重
  4. 原始数组保护:如果需保留原数组,操作前可深拷贝:
const newList = [...new Set(originalArray)];

响应式原理说明:

Vue 3 使用 Proxy 实现响应式,直接修改数组元素 (list.value[0] = ...) 或使用 push() 等方法可触发更新,但去重操作需要生成新数组并整体替换才能确保视图正确更新。

选择方法时,简单数组用 Set 最简洁,对象数组推荐用 Map 实现高效去重。

在Vue 3中对对象数组进行去重(依据所有属性值相同),可以通过以下方法实现。这里提供两种常见方案,推荐使用基于序列化与Set去重使用filterfindIndex的方法:

Vue 3对对象数组进行去重的方案

方案1:使用JSON序列化与Set(简单高效,适用于扁平对象)

import { ref, watchEffect } from 'vue';

const originalArray = ref([
  { id: 1, name: 'Alice', age: 30 },
  { id: 2, name: 'Bob', age: 25 },
  { id: 1, name: 'Alice', age: 30 }, // 重复项
]);

// 去重逻辑
const deduplicatedArray = ref([]);
watchEffect(() => {
  const seen = new Set();
  deduplicatedArray.value = originalArray.value.filter(obj => {
    // 序列化对象(按键排序避免属性顺序不同导致的误判)
    const serialized = JSON.stringify(obj, Object.keys(obj).sort());
    return seen.has(serialized) ? false : seen.add(serialized);
  });
});

console.log(deduplicatedArray.value); 
// 输出: [{id:1, name:'Alice', age:30}, {id:2, name:'Bob', age:25}]

说明

  1. 使用JSON.stringify将对象转换为字符串,并通过Object.keys().sort()统一属性顺序。
  2. 利用Set检测重复的序列化字符串,过滤重复项。

方案2:使用filter与自定义比较函数(支持嵌套对象,但性能较低)

import { ref, watchEffect } from 'vue';

// 深度比较两个对象是否相等
const isEqual = (obj1, obj2) => {
  const keys1 = Object.keys(obj1), keys2 = Object.keys(obj2);
  if (keys1.length !== keys2.length) return false;
  return keys1.every(key => {
    const v1 = obj1[key], v2 = obj2[key];
    if (typeof v1 === 'object' && v1 !== null && typeof v2 === 'object' && v2 !== null) {
      return isEqual(v1, v2); // 递归比较嵌套对象
    }
    return v1 === v2;
  });
};

const originalArray = ref([...]); // 原始数组

const deduplicatedArray = ref([]);
watchEffect(() => {
  deduplicatedArray.value = originalArray.value.filter((obj, index, arr) => {
    return index === arr.findIndex(item => isEqual(item, obj));
  });
});

说明

  1. 自定义isEqual函数递归比较对象所有属性(包括嵌套)。
  2. 通过findIndex找到第一个匹配项,保留首次出现的对象。

方案3:使用Vue 3的响应式工具(组合式函数封装)

import { ref, computed } from 'vue';

// 封装为可复用的组合式函数
export function useDeduplicateArray(array) {
  return computed(() => {
    const seen = new Set();
    return array.value.filter(obj => {
      const serialized = JSON.stringify(obj, Object.keys(obj).sort());
      return seen.has(serialized) ? false : seen.add(serialized);
    });
  });
}

// 在组件中使用
const originalArray = ref([...]);
const deduplicatedArray = useDeduplicateArray(originalArray);

注意事项:

序列化方法的局限性
JSON.stringify会忽略函数、undefined和循环引用,仅适用于可序列化数据。

性能考虑
大数据量时推荐使用方案1(Set+序列化),避免嵌套循环(方案2的findIndex时间复杂度为O(n²))。

响应式处理
使用watchEffectcomputed确保响应式数据变化时自动更新去重结果。

根据实际需求选择合适方案,扁平对象推荐方案1,嵌套对象可考虑方案2或使用第三方库(如lodash.isEqual)。

数组去重工具:arrayDeduplicateUtils.ts

import { isEqual } from "lodash-es";
 
/**
 * 简单数组去重
 * @param array 简单数组,如:["a", "b", "c", "b", "a"]、[1, 2, 3, 2, 1]
 * @returns 去重的简单数组,如:["a", "b", "c"]、[1, 2, 3]
 */
export const deduplicateSimpleArray = (array: string[] | number[]) => {
  // 方法1:使用 Array.from + Set
  // return Array.from(new Set(array as any)) as string[] | number[];
 
  // 方法2:使用 扩展运算符 ... + Set
  if (array.length === 0) {
    return [];
  }
  // 判断数组的第一个元素是否为字符串类型
  if (typeof array[0] === "string") {
    return [...new Set(array as string[])];
  } else {
    return [...new Set(array as number[])];
  }
};
 
/**
 * 对象数组去重,通过主键值去重,使用 Map
 * @param array 对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 35 }]
 * @returns 去重的对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }]
 */
export const deduplicateObjectArrayByKey = (array: any[], key: string) => {
  const seen = new Map();
  return array.filter((item) => (seen.has(item[key]) ? false : seen.set(item[key], true)));
};
 
/**
 * 对象数组去重,通过对象所有属性值都相同去重,使用 JSON 序列化与 Set(适用扁平对象,简单高效)
 * 1、使用 JSON.stringify 将对象转换为字符串,并通过 Object.keys().sort() 统一属性顺序。
 * 2、使用 Set 检测重复的序列化字符串,过滤重复项。
 * @param array 对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 35 }]
 * @returns 去重的对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 2, name: 'Bob', age: 35 }]
 */
export const deduplicateObjectArray = (array: any[]) => {
  const seen = new Set();
  return array.filter((item) => {
    // 序列化对象(按键排序避免属性顺序不同导致的误判)
    const serialized = JSON.stringify(item, Object.keys(item).sort());
    return seen.has(serialized) ? false : seen.add(serialized);
  });
};
 
/**
 * 对象数组去重,通过对象所有属性值都相同去重,使用 filter、findIndex 与 lodash-es.isEqual(支持嵌套对象,性能较低)
 * 1、使用 lodash-es.isEqual 深度比较两个对象是否相等。
 * 2、使用 findIndex 找到第一个匹配项,保留首次出现的对象。
 * @param array 对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 35 }]
 * @returns 去重的对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 2, name: 'Bob', age: 35 }]
 */
export const deduplicateObjectArrayOfNested = (array: any[]) => {
  return array.filter((item, index, arr) => {
    return index === arr.findIndex((item2) => isEqual(item2, item));
  });
};

数组去重组合式函数 hook:useArrayDeduplicate.ts

import {
  deduplicateObjectArray,
  deduplicateObjectArrayByKey,
  deduplicateObjectArrayOfNested,
  deduplicateSimpleArray
} from "@/utils/arrayDeduplicateUtils";
import { computed } from "vue";
 
/**
 * 数组去重,组合式函数 hook
 */
export const useArrayDeduplicate = () => {
  /**
   * 简单数组去重
   * @param array 简单数组,如:["a", "b", "c", "b", "a"]、[1, 2, 3, 2, 1]
   * @returns 去重的简单数组,如:["a", "b", "c"]、[1, 2, 3]
   */
  const deduplicateSimpleArrayHook = (array: string[] | number[]) => {
    return computed(() => {
      return deduplicateSimpleArray(array);
    });
  };
 
  /**
   * 对象数组去重,通过主键值去重,使用 Map
   * @param array 对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 35 }]
   * @returns 去重的对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }]
   */
  const deduplicateObjectArrayByKeyHook = (array: any[], key: string) => {
    return computed(() => {
      return deduplicateObjectArrayByKey(array, key);
    });
  };
 
  /**
   * 对象数组去重,通过对象所有属性值都相同去重,使用 JSON 序列化与 Set(适用扁平对象,简单高效)
   * 1、使用 JSON.stringify 将对象转换为字符串,并通过 Object.keys().sort() 统一属性顺序。
   * 2、使用 Set 检测重复的序列化字符串,过滤重复项。
   * @param array 对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 35 }]
   * @returns 去重的对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 2, name: 'Bob', age: 35 }]
   */
  const deduplicateObjectArrayHook = (array: any[]) => {
    return computed(() => {
      return deduplicateObjectArray(array);
    });
  };
 
  /**
   * 对象数组去重,通过对象所有属性值都相同去重,使用 filter、findIndex 与 lodash-es.isEqual(支持嵌套对象,性能较低)
   * 1、使用 lodash-es.isEqual 深度比较两个对象是否相等。
   * 2、使用 findIndex 找到第一个匹配项,保留首次出现的对象。
   * @param array 对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 35 }]
   * @returns 去重的对象数组,如:[{ id: 1, name: 'Tom', age: 30 }, { id: 2, name: 'Bob', age: 25 }, { id: 2, name: 'Bob', age: 35 }]
   */
  const deduplicateObjectArrayOfNestedHook = (array: any[]) => {
    return computed(() => {
      return deduplicateObjectArrayOfNested(array);
    });
  };
 
  return {
    /** 简单数组去重 */
    deduplicateSimpleArrayHook,
    /** 对象数组去重,通过主键值去重,使用 Map */
    deduplicateObjectArrayByKeyHook,
    /** 对象数组去重,通过对象所有属性值都相同去重,使用 JSON 序列化与 Set(简单高效,适用于扁平对象) */
    deduplicateObjectArrayHook,
    /** 对象数组去重,通过对象所有属性值都相同去重,使用 filter、findIndex 与 lodash-es.isEqual(支持嵌套对象,性能较低) */
    deduplicateObjectArrayOfNestedHook
  };
};

以上就是Vue3中对数组去重的方法总结的详细内容,更多关于Vue3数组去重的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文