JS数组专题2️⃣ ➖ 数组去重

本文深入探讨了JavaScript数组去重的多种方法,包括两层循环、单层循环、使用对象键、排序比较、indexOf和ES6特性等。每种方法都有其优缺点,适用于不同的场景。

JS数组专题2️⃣ ➖ 数组去重

距离上次发文,已经有一段时间了,最近工作比较忙,这不眼看快双十一了,就相当于给大家一些福利吧!

装逼图

一、什么是数组去重

简单说就是把数组中重复的项删除掉,你 GET 到了吗 ?下面我将简单介绍下几种基本的方法及其优缺点。

二、方法汇总

  • 两层循环

** 无相同值直接 push 进新数组,有相同的值则直接跳过本次内部循环 **

/*
 * @param {Array} arr    -要去重的数组
 * @param {Array} result -初始化结果数组
 */
const unique = (arr, result = []) => {
  const len = arr.length;
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (arr[i] === arr[j]) {
        // 相等则直接跳过
        j = ++i;
      }
    }
    result.push(arr[i]);
  }
  return result;
}

** 相同的做标记,与新数组作比较,没有则插入 **

/*
 * @param {Array} arr    -要去重的数组
 * @param {Array} result -初始化结果数组
 */
const unique = (arr, result = []) => {
  result.push(arr[0]);
  const len = arr.length;
  let rLen = result.length;

  for (let i = 1; i < len; i++) {
    let flag = false;
    for (var j = 0; j < rLen; j++) {
      if (arr[i] === result[j]) {
        flag = true;
        break;
      }
    }
    if (!flag) {
      rLen++;
      result.push(arr[i]);
    }
  }
  return result;
}

** 原地算法(在数组本身操作) **

const unique = arr => {
  const len = arr.length;
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (arr[i] == arr[j]) {
        arr.splice(j,1);
        len--;
        j--;
      }
    }
  }
  return arr;
};

看似代码代码简单,实则内存占用高,不实用

  • 单层循环

** 对象键不能重复 **

const unique = (arr, result = []) => {
  const obj = {};
  const len = arr.length;
  for (let i = 0; i< len; i++) {
    if (!obj[arr[i]]) {
      // 键没有,则添加
      obj[arr[i]] = 1;
      result.push(arr[i]);
    }
  }
  return result;
};

这种方法无法判断 '1'1 等类型,解决方案:

  1. 添加判断数据类型,比如 typeofobj[typeof arr[i] + arr[i]] 不过这还是判断不了 ['1'][1],因为这被相加后,结果都一样
  2. 添加 JSON.stringify() 对结果进行去格式化,这时就可以判断了

** 排序后比较前后两位,不相等则添加进新数组 **

const unique = (arr, result = []) => {
  arr.sort();
  result.push(arr[0]);
  const len = arr.length;
  let rLen = result.length;
  for (let i = 1; i < len; i++) {
    if (arr[i] !== result[rLen - 1]) {
      result.push(arr[i]);
      rLen++;
    }
  }
  return result;
}

方法比较直接

** 原地算法(排序后比较前后两位,相等则删除) **

const unique = (arr) => {
  arr.sort();
  let len = arr.length;
  for (let i = 1; i < len; i++) {
    if (arr[i] === arr[i - 1]) {
      arr.splice(i, 1)
      len--;
    }
  }
  return arr;
}

不消耗额外的空间

  • 偷懒的节奏

** indexOf 判断数组元素第一次出现的位置是否相同 **

const unique = (arr, result) => {
  arr.forEach((item, index, array) => {
    if(array.indexOf(item) === index) {
      result.push(item);
    }
  });
  return result;
}

// 使用ES6 filter
const unique = (arr) =>
  arr.filter((item, index) =>  array.indexOf(item) === index);

使用ES6 方法更简洁性能更好

** indexOf 的ES6 方法通过 includes 判断新数组中是否有该元素 **

const unique = (arr, result) => {
  arr.forEach((item, index, array) => {
    if(!result.includes(item)) {
      // 或者 result.indexOf(item) === -1
      result.push(item);
    }
  });
  return result;
}

建议使用 includes

** Map 数据结构,不懂 Map 的自行解决,传送门 **

const unique = arr => {
  const map = new Map();
  return arr.filter((item) => !map.has(item) && map.set(item, 1));
}

对象关系映射可以设置不同类型的键,使之很快能收集 arr 中不一样的数据

** Set 数据结构,不允许出现重复数据,而且 Set 支持解构 传送门 **

const unique = arr => Array.from(new Set(arr));

// 或者通过 ES6 的 ...解构
const unique = arr => [...new Set(arr)];

简单粗暴

** reduce,给定初始值,根据数组循环给出最终值 **

const unique = (arr, result = []) => arr.reduce((prev,curr) => prev.includes(curr) ? prev : [...prev, curr], result);

三、总结

方法已经说了差不多了,就看你怎么用了,其中有一些差不多的方法,只是给了说明,没给具体的例子,希望大家自己去试一下,告辞!

<think>我们正在解决JSON解析错误:"UnexpectedtokenIinJSONatposition1"这个错误通常意味着在JSON字符串的第一个位置遇到了一个意料之外的字符(这里是大写字母'I')。JSON字符串应该以有效的JSON值开始(如对象以'{'开始,数组以'['开始,字符串以'"'开始,数字以数字字符开始等)。可能的原因:1.实际传递的字符串并不是有效的JSON,可能在开头处有额外的字符(如空格、换行、注释或多余的字符)。2.可能传递了一个非JSON的字符串(如JavaScript对象字面量、HTML、纯文本等)。3.如果是从服务器返回的数据,可能服务器返回了错误信息(如HTML错误页面),而不是预期的JSON。解决方案步骤:1.检查JSON字符串:在尝试解析之前,将字符串打印出来(或记录日志)以查看其实际内容。2.确保字符串是有效的JSON:可以使用在线JSON验证工具(如JSONLint)来验证。3.检查位置1的字符:由于错误提到位置1(即第一个字符),检查这个位置是否是预期的字符(如'{'或'[')。4.处理可能的空白字符:使用`trim()`方法除字符串两端的空白,然后再解析。5.错误处理:使用`try...catch`块来捕获解析错误并提供更友好的错误信息。示例代码(JavaScript):```javascripttry{//假设jsonString是我们需要解析的字符串jsonString=jsonString.trim();//除前后空白constobj=JSON.parse(jsonString);//解析成功,继续使用obj}catch(error){console.error('解析JSON失败:',error);console.log('出错的JSON字符串:',jsonString);}```如果第一个字符是'I',那么字符串可能以"I"开头,这通常不是有效的JSON。常见的以I开头的情况可能是服务器返回了一个错误消息字符串,例如:"InternalServerError"或者"Invalidrequest"这时,我们需要检查后端服务是否正常运行,并返回了正确的JSON格式响应。如果是从服务器获取JSON,检查网络请求的响应:-确保请求成功(HTTP状态码200)-检查响应头中的Content-Type是否为`application/json`如果使用的是fetchAPI:```javascriptfetch('url').then(response=>{if(!response.ok){thrownewError('网络响应不正常');}returnresponse.text();//先作为文本获取}).then(text=>{try{constdata=JSON.parse(text);//使用解析后的data}catch(e){console.error('解析响应内容为JSON失败:',e);console.log('响应文本:',text);}}).catch(error=>{console.error('请求失败:',error);});```另外,如果JSON字符串中包含了注释,则JSON.parse无法解析(因为JSON规范不支持注释)。此时需要除注释(或者服务器端不应该返回带注释的JSON)。关于引用部分,用户提供的引用并不直接相关(引用[1]是TypeScript的项目引用配置,引用[2]是Python示例,引用[3]是GitHub认证提示,引用[4]是HTML标签片段),所以忽略它们。因此,总结解决方案:-检查JSON字符串内容,尤其是开头-除前后空白-确认返回的是正确的JSON格式-使用try-catch处理解析错误</think> 为了解决JSON解析错误“Unexpected token I in JSON at position 1”,这个问题通常发生在尝试解析非标准JSON数据时。以下是完整的排查和解决方案: ### 错误原因分析 1. **位置1的无效字符**:错误中的`I`出现在JSON字符串的第一个字符位置(position 1),而有效的JSON开头应为: - `{`(对象开始) - `[`(数组开始) - `"`(字符串值) - 数字或布尔值 2. **常见触发场景**: - 服务器返回了错误信息(如“Internal Server Error”)而非JSON - API响应包含未处理的HTML/XML头(如`<!DOCTYPE>`) - 前端未正确处理响应内容类型 - 控制台打印的调试信息被错误解析 ### 解决方案步骤 #### 1️⃣ 验证JSON数据完整性 ```javascript // 获取原始响应文本并打印 fetch('api-url') .then(response => response.text()) // 先转为文本 .then(rawText => { console.log("原始响应:", rawText); // 关键!检查实际内容 try { const data = JSON.parse(rawText); // 成功解析后处理数据 } catch (e) { console.error("解析失败:", e.message); } }); ``` #### 2️⃣ 处理常见非JSON响应 ```javascript // 处理可能的HTTP错误响应 if (!response.ok) { // 状态码非200-299 const errorText = await response.text(); if (errorText.startsWith("I")) { // 以I开头说明是错误信息 throw new Error(`服务端错误:${errorText}`); } } ``` #### 3️⃣ 预处理特殊字符(强制转换) ```javascript // 删除JSON字符串前的无效字符 function safeParse(jsonStr) { const cleaned = jsonStr.replace(/^[^[{"]+/, ''); return JSON.parse(cleaned || '{}'); // 避免空字符串 } // 使用示例 safeParse("Internal Error: { 'code': 500 }"); // → 解析成功 ``` #### 4️⃣ 检查Content-Type头 确保服务端返回正确的响应头: ```http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 ✅ 必须项 ``` #### 5️⃣ 后端修复建议 ```javascript // Express.js示例:确保返回纯JSON app.get('/data', (req, res) => { res.setHeader('Content-Type', 'application/json'); res.status(200).json({ data: "valid" }); // 勿用res.send("Invalid") }); ``` ### 调试技巧 ```javascript // 快速检测首字符 console.log(` 首字符: ${rawData.charAt(0)} 前10字符: ${rawData.substring(0,10)} `); ``` ### 预防措施 - 始终用`try/catch`包裹`JSON.parse` - 使用axios等库自动处理响应转换 - 为API请求添加超时和试机制 - 实现请求拦截器统一处理错误响应 > 此错误表明解析器在JSON字符串起始位置遇到意外字符“I”[^1]。该字符通常出现在错误消息中(如“Internal Server Error”)[^3],而非有效的JSON数据结构。建议通过检查原始响应内容和修复服务端实现来解决根本问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值