javascript 系列- 数组问题汇总

598 阅读5分钟

是什么

开发中处理数组对象,会遇到一些问题。

以下做个笔记

  1. 问题一:数组去重复
  2. 问题二:数组对象去重复
  3. 问题三:数组替换值
  4. 问题四:数组合并
  5. 问题五:数组删除虚值
  6. 问题六:数组取随机值
  7. 问题七:数组求和
  8. 问题八:数组反转
  9. 问题九:数组转对象
  10. 问题十:数组对象取指定键值
  11. 问题十一:数组转字符串
  12. 问题十二:数组合并
  13. 问题十三:数组交集
  14. 问题十四:数组差集
  15. 问题十五:数组遍历
  16. 问题十六:判断数组中是否有符合条件的值
  17. 问题十七:判断数组中所有元素是否都符合条件
  18. 问题十八:找到第一个符合条件的元素/下标
  19. 问题十九:数组浅复制/深复制
  20. 问题二十:数组最大最小值
  21. 问题二十一:数组元素个数统计
  22. 问题二十二:数组元素位置统计
  23. 问题二十三:数组按元素分组
  24. 问题二十四:数组url 参数序列化
  25. 问题二十五:数组url 参数反序列化
  26. 问题二十六:数组扁平
  27. 问题二十七:数组 reduce 函数
  28. 问题二十八:数组对象获取下标
  29. 问题二十九:数组递归树形
  30. 问题三十:数组 reduce 生成html

返回新数组,不改变原数组: join concat slice map every some filter forEach reduce

返回新数组,改变原数组:push pop shift unshift reverse sort slice

问题一:数组去重复

const unique = arr => arr.filter((element, index, self) => self.indexOf(element) === index);

问题二:数组对象去重复

const arr = [
    { id: 1, name: '张三' },
    { id: 2, name: '李四' },
    { id: 11, name: '王五' },
    { id: 1, name: '张三' },
    { id: 11, name: '王五' },
    { id: 3, name: '李四' }
];
const unique = (arr, name) => {
    let cache = [];
    for(let item of arr){
        if(cache.find(v => v[name] === item[name])) {
            continue;
        }
        cache.push(item);
    }
    return cache;
}

const filterNonUniqueBy = (arr, fn) =>
  arr.filter((val, index) =>
    arr.every((x, y) => (index === y) === fn(val, x, index, y))
  );

// filterNonUniqueBy(arr,(a, b) => a.id === b.id)
console.log(unique(arr, 'id')); 
// [{id: 1, name: "张三"}, {id: 2, name: "李四"}, {id: 11, name: "王五"}, {id: 3, name: "李四"}]

问题三:数组替换值

var cache = ['wxh','wxh2','wxh3','wxh4','wxh5']
cache.splice(0,2,'wxh','wxh')
console.log(cache) // ['wxh','wxh','wxh3','wxh4','wxh5']

问题四:数组合并

var array = [1,2,2,3,5,6];
var array2 = [1,2,2,3,5,6];
var cache = [...array,...array2]

问题五:数组删除虚值

var array = [1,2,2,3,5,6];
// 在 JS 中,虚值有 false, 0,'', null, NaN, undefined。咱们可以 .filter() 方法来过滤这些虚值。
var cache = array.filter(Boolean);

问题六:数组取随机值

var array = [1,2,2,3,5,6];
var cache = array[(Math.floor(Math.random() * (array.length)))];

问题七:数组求和

var array = [1,2,2,3,5,6];
var cache = array.reduce((x,y) => x + y);

问题八:数组反转

function Reverse(arr) {
    return arr.reduceRight((item,value) => (item.push(value),item),[]);
}
//[5, 4, 3, 2, 1]

问题九:数组转对象

const cache = [1, 2, 3, 4];
const arrayToObject = {...arr}; // {0: 1, 1: 2, 2: 3, 3: 4}


const cache = {'name':'wxh', 'title':'hello world'}
const ObjectToArray = Object.getOwnPropertyNames(cache); // ["name", "title"]
const ObjectToArray = Object.keys(cache).map(function(i){return cache[i]}); // ["wxh", "hello world"]

问题十:数组对象取指定键值

function GetKeys(obj = {}, keys = []) {
    return Object.keys(obj).reduce((t, v) => (keys.includes(v) && (t[v] = obj[v]), t), {});
}
const cache = { a: 1, b: 2, c: 3, d: 4 };
const keyword = ["a", "d"];
GetKeys(cache, keyword); // { a: 1, d: 4 }

问题十一:数组转字符串

const cache = [1, 2, 3, 4];
const str = cache.join(","); // 数组转字符串
const arr = str.split(","); // 字符串转数组

问题十二:数组合并

const cache = [1, 2, 3, 4];
const arr = [...cache, ...cache, ...cache]

问题十三:数组交集

const cache = [0, 1, 2, 3, 4, 5]
const b = [3, 4, 5, 6, 7, 8]
const joinValue = [...new Set(cache)].filter(item => b.includes(item)) // [3, 4, 5]


let cache = [{a:'1',b:'12'}, {a:'0', b:'12'}]
let cache1 = [{a:'2',b:'23'}, {a:'0', b:'12'}]
let cache2 = cache.map(item=>item.a)
let cache3 = cache1.filter(info=>{
return new Set(cache2).has(info.a)
})
console.log(cache3) // [{a:'0', b:'12'}]
  1. 问题十四:数组差集
const a = [0, 1, 2, 3, 4, 5]
const b = [3, 4, 5, 6, 7, 8]
const diffValues = [...new Set([...a, ...b])].filter(item => !b.includes(item) || !a.includes(item)) 
// [0, 1, 2, 6, 7, 8]
  1. 问题十五:数组遍历
// 数组遍历
const cache = [0, 1, 2, 3, 4, 5]
console.log(cache.map(i => i));

const copy = [];
cache.forEach(function(val, index) {
    copy.push(val);
})

for (var i in cache){
    console.log(i,":",cache[i]);
}

// 对象遍历
const cache = [{a:'1',b:'12'}, {a:'0', b:'12'}];
Object.keys(cache).forEach(function(key){
     console.log(key,cache[key]);
});
Object.getOwnPropertyNames(cache).forEach(function(key){
    console.log(key,cache[key]);
});

for(var i of cache) {
    console.log(i,":",cache[i]);
}

// 含Symbol属性
Reflect.ownKeys(cache).forEach(function(key){
    console.log(key,cache[key]);
});

问题十六:判断数组中是否有符合条件的值

// 数组
const cache = [1, 2, 3, 4, 5]
const hasNum = cache.some(item => typeof item === 'number')

// 对象
const reducedFilter = (data, keys, fn) =>
  data.filter(fn).map((el) =>
    keys.reduce((acc, key) => {
      acc[key] = el[key];
      return acc;
    }, {})
  );
const dataFilter = [
  {
    id: 1,
    name: "john",
    age: 24,
  },
  {
    id: 2,
    name: "mike",
    age: 50,
  },
];
console.log(
  "按照条件筛选数据对象",
  reducedFilter(dataFilter, ["id", "name"], (item) => item.age > 24)
);

问题十七:判断数组中所有元素是否都符合条件

const cache = [1, 2, 3, 4, 5]
const isAllNum = cache.every(item => typeof item === 'number')

问题十八:找到第一个符合条件的元素/下标

const cache = [1, 2, 3, 4, 5]
const findItem = cache.find(item => item === 3) // 返回子项
const findIndex = cache.findIndex(item => item === 3) // 返回子项的下标

问题十九:数组浅复制/深复制

const cache = [1, 2, 3]
const arrClone = [...cache]
const arrClone = Array.from(cache);
const arrClone = cache.slice(0, cache.length)

const cache = { a: 1 }
const objClone = { ...cache }

function deepClone(object) {
  var clone = {};
  for (var key in object) {
    var value = object[key];
    if (typeof(value) !== 'object') {
      clone[key] = value;
    } else {
      clone[key]=deepClone(value);
    }
  }
  return clone;
} 
const objClone = deepClone(cache)

问题二十:数组最大最小值

function Max(arr = []) {
    return arr.reduce((t, v) => t > v ? t : v);
}

function Min(arr = []) {
    return arr.reduce((t, v) => t < v ? t : v);
}

问题二十一:数组元素个数统计

function Count(arr = []) {
    return arr.reduce((t, v) => (t[v] = (t[v] || 0) + 1, t), {});
}
const cache = [0, 1, 1, 2, 2, 2];
Count(cache); // { 0: 1, 1: 2, 2: 3 }

问题二十二:数组元素位置统计

function Count(arr = [], val) {
    return arr.reduce((t, v, i) => (v === val && t.push(i), t), []);
}
const cache = [2, 1, 5, 4, 2, 1, 6, 6, 7];
Count(cache, 2); // [0, 4]

问题二十三:数组按元素分组

function Group(arr = [], key) {
    return key ? arr.reduce((t, v) => (!t[v[key]] && (t[v[key]] = []), t[v[key]].push(v), t), {}) : {};
}

const cache = [
    { city: "GZ", name: "YZW", age: 127 },
    { city: "GZ", name: "TYJ", age: 125 },
    { city: "SZ", name: "AAA", age: 123 },
    { city: "FS", name: "BBB", age: 121 },
    { city: "SZ", name: "CCC", age: 119 }
]; 
// 以city作为分组依据
Group(cache, "city"); // { GZ: Array(2), SZ: Array(2), FS: Array(1) }

问题二十四:数组url 参数序列化

function paramsUrl(search = {}) {
    return Object.entries(search).reduce(
        (t, v) => `${t}${v[0]}=${encodeURIComponent(v[1])}&`,
        Object.keys(search).length ? "?" : ""
    ).replace(/&$/, "");
}
paramsUrl({ age: 27, name: "test" }); // "?age=27&name=test"

问题二十五:数组url 参数反序列化

function ParseUrlSearch() {
    return location.search.replace(/(^\?)|(&$)/g, "").split("&").reduce((t, v) => {
        const [key, val] = v.split("=");
        t[key] = decodeURIComponent(val);
        return t;
    }, {});
}
// https://www.baidu.com?age=27&name=test
ParseUrlSearch() // { age: "27", name: "test" }

问题二十六:数组扁平

function Flat(arr = []) {
    return arr.reduce((t, v) => t.concat(Array.isArray(v) ? Flat(v) : v), [])
}

const cache = [0, 1, [2, 3], [4, 5, [6, 7]], [8, [9, 10, [11, 12]]]];
Flat(cache); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

问题二十七:数组 reduce 函数

const cache = [0, 1, 2, 3];

// 代替map:[0, 2, 4, 6]
const a = cache.map(v => v * 2);
const b = cache.reduce((t, v) => [...t, v * 2], []);

// 代替filter:[2, 3]
const c = cache.filter(v => v > 1);
const d = cache.reduce((t, v) => v > 1 ? [...t, v] : t, []);

// 代替map和filter:[4, 6]
const e = cache.map(v => v * 2).filter(v => v > 2);
const f = cache.reduce((t, v) => v * 2 > 2 ? [...t, v * 2] : t, []);


const cache = [
    { score: 45, subject: "chinese" },
    { score: 90, subject: "math" },
    { score: 60, subject: "english" }
];

// 代替some:至少一门合格
const isAtLeastOneQualified = cache.reduce((t, v) => t || v.score >= 60, false); // true

// 代替every:全部合格
const isAllQualified = cache.reduce((t, v) => t && v.score >= 60, true); // false

问题二十八:数组对象获取下标

const sortedIndexBy = (arr, n, fn) => {
  const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
  const val = fn(n);
  const index = arr.findIndex((el) =>
    isDescending ? val >= fn(el) : val <= fn(el)
  );
  return index === -1 ? arr.length : index;
};
console.log(
  "获取下标",
  sortedIndexBy([{ x: 14 }, { x: 35 }], { x: 35 }, (o) => o.x) // 1
); 

问题二十九:数组递归树形

const nest = (items, id = null, link = "parent_id") =>
  items
    .filter((item) => item[link] === id)
    .map((item) => ({ ...item, children: nest(items, item.id, link) }));
const comments = [
  { id: 1, parent_id: null },
  { id: 2, parent_id: 1 },
  { id: 3, parent_id: 1 },
  { id: 4, parent_id: 2 },
  { id: 5, parent_id: 4 },
];
const nestedComments = nest(comments);

console.log("递归树形", nestedComments);

问题三十:数组 reduce 生成html

// 后端返回数据
const datas = {
  'name': [
    'wxh',
    'wxh',
    'wxh',
  ],
  'age': [
    'wxh',
    'wxh',
    'wxh',
  ]
}

const _data = Object.entries(datas).reduce((prev, cur) => {
  const values = cur[1].reduce((prev, cur) => `${prev}<p>${cur}</p>`, '')
  return `${prev}
  <li>
      <p>${cur[0]}</p>
      ${values}
    </li>`
}, '')

const html = `
  <ul class="nlp-notify-body">
    ${_data}
  </ul>
`
console.log(html);