计算全国所有城市间的距离

222 阅读2分钟

最近听到同事有一份 全国城市经纬度.csv,需求是处理为一份所有城市间距的 csv 文件。恰好对 turf 了解些,就帮他们写了这个小功能,顺便记录一下方便下次直接用。

拆分步骤

有时候会看到大家可能有 csv & json 互转的需求,所以这次也做了两者的互转来完成,很简单要解决的也就是这三步:

  1. csv2json
    • node 核心模块 fs 读取文件(如果假设还不了解最常见的模块,建议看一下 朴灵老师的《深入浅出nodejs》
    • csv 数据流转码生成熟悉的 json 数据结构
  2. turfjs 计算每两个城市间距离
  3. json2csv
    • 了解输出 csv 文件字符串规则
csv2json

fs.readFile 读取文件为数据流

TextDecoder 接口表示一个文本解码器,将字节流作为输入,并提供码位流作为输出。转码为json 关键

const fs = require("fs");

const csv2json = () => {
  // 简单使用同步读取
  let csvData;
  try {
    csvData = fs.readFileSync("filename.csv"); // 数据流
  } catch (err) {
    console.log(err);
  }
  if (!csvData) return;

  // 解码 TextDecoder('utf-8').decode 'utf-8' 防止乱码
  const csvArr = new TextDecoder("utf-8").decode(file).split("\r\n");

  // 转换为更容易理解的 json
  const json = [];
  const head = csvArr.shift().split(",");

  csvArr.forEach((item) => {
    const arr = item.split(",");
    const resItem = {};
    head.forEach((key, i) => (resItem[key] = arr[i]));
    json.push(resItem);
  });

  return json;
};
计算距离
const turf = require('@turf/turf');

// 两点之间距离
const caculDistance = (objA, objB) => {
  if (!objA.lng || !objA.lat || !objB.lng || !objB.lat) return;
  const from = turf.point([Number(objA.lng), Number(objA.lat)]);
  const to = turf.point([Number(objB.lng), Number(objB.lat)]);
  return turf.distance(from, to, { units: "kilometers" });
};

const calc = (csvList) => {
  const res = [];
  
  csvList.forEach((item, index) => {
    const resItem = { name: item.name, adcode: item.adcode };
    csvList.forEach((d, i) => {
      resItem[d.name] = caculDistance(d, item);
    });
    res.push(resItem);
  });
  return res;
};
数据生成csv

const { promises: { readFile, writeFile, mkdir } } = require('fs');

const json2csv = async (list) => {
  // csv 字符串
  let content = "";

  // 表内容(主体)转换为 csv 字符串
  list.forEach((item, index) => {
    if (index === 0) {
      // 表头转换
      content += `\ufeff${Object.keys(item).join(",")}\n`; // 【\ufeff】 防乱码;【,】 换列;【\n】换行
    }
    content += Object.values(item).join(",") + "\n";
  });

  // 输出 `.csv` 文件
  await writeFile("./filename.csv", content);
};

计算距离并输出 .csv 文件

(async () => {
    // csv 转 json
    const json = await csv2json();
    // 处理为目标数据
    const calcJson = calc(json);
    // json 转 csv 并输出
    json2csv(calcJson);
})()