月度归档:2022年08月

别只顾着低头拿牌

别只顾着低头拿牌

对于大部分普通的青年人而言,最大的问题不是不努力,而是没有努力的方向。

我们常看到青年们在学校中追逐着自己身边人的脚步,别人做什么,自己也做什么。他人拿到了什么样的奖项,我就一定要拿到什么样的奖项。

但从未思考过,到底什么是想要的?无限制的拿牌只会让你在焦虑当中深深的陷下去 —— 毕竟感觉自己拿到了更多的牌,应该就能赢了。

现实往往不是那么的简单,我们看到别人能赢,是因为他规划好了自己的路线,而我们没有按照自己的规划去拿牌,最后虽然手上牌多,但不能帮助自己很好的达成目标,一切都是白搭。

更好的方式是 —— 想明白自己想要的是什么,然后在想要的方向上努力去拿牌,然后达成自己的目标,成功和牌。

以终为始,很重要。

线性内容与非线形内容:兼谈电子书与实体书

线性内容与非线形内容:兼谈电子书与实体书

今天在在读网络空间的兴衰的时候,里面的一句话引起我的注意

人们在阅读文字时,常常快速扫描文字,找到感兴趣的部分再按照顺序细致阅读,这也达到了随机访问的效果。而音频与视频不能快速扫描,只能依然按照时间顺序快进或快退,来搜寻想要的内容,有较强的线性。

OrangeCLK

而我们所熟悉的音乐播放器的概念,也不过是更加方便的切换帧

现代音频视频播放器提供了进度条操作的接口,可以在时间轴上选取播放时间,有了一定随机读取的功能。但大体上音频与视频仍然是线性媒体,它只有按照时间顺序播放时才能提供意义,计算机提供的操作接口只是让人可以选择播放起点。音频视频中各帧内容只有时间关系,没有其他联系。

上面这段描述,突然让我意识到了我自己阅读习惯的一部分 —— 关于买书。

我算是一个比较喜欢买书的人,每年基本上都会买一些实体书和电子书来看,电子书我有4部 ,实体书有近 200 本。

我买的电子书和实体书也会有明确的方向倾向:

  • 工具书、计算机相关的,大多买实体书 、 PDF
  • 社科类图书、传记类图书,大多买 Kindle 电子书 / 微信

工具书买实体,是因为我在看工具书的时候会需要从目录快速导航到某个具体的细节,然后在这个细节里进一步快速跳转。在读这些工具书的时候,我的目标就是 —— 快速读完,然后解决问题,合上书。

除了工具书之外,我还会把一些我在电子书当中看到觉得不错,打算长期持续性阅读的传记等,买成实体书以便随时翻阅。

而社科类、传记类的图书,由于其内容和时间序、顺序阅读强相关,没有那么强的随意跳跃的诉求,携带方便的电子书就成了最佳的选择。

当时不明白自己为什么这么样选择,现在看看,大概是因为信息本身的特质决定的。

运用深度优先和广度优先算法获取更多的信息

运用深度优先和广度优先算法获取更多的信息

我平时会看很多的文章,这些文章成为我不断的创作的重要的灵感来源和信息收集的来源,因此,我对于信息的收集和整理也颇为关注,只为收获更多的信息。

在实际的阅读当中,我会采用深度与广度优先结合的方式,来遍历我所看的文章、图书,从而获得一个更大范围要阅读的内容。

主题 · 深度优先遍历

我的阅读往往是从某一个主题开始的,通过搜索引擎,找到搜索引擎当中排行靠前的文章,作为我的主题文章。

搜索获得主题文章

在阅读主题文章时,我会进行广度优先遍历,将文章当中提到的关联文章、参考链接用新标签页面打开放在后台,等待稍后处理完当前页面再进行阅读。这个时候,我阅读的文章就会从原本的一篇文章,变为 1 + 3 篇文章;

在阅读完主题文章后,再依次阅读其相关文章 A、B、C。并在 A、B、C 的基础上,进一步挖掘相关文章 D、E、 F、G、H。此时,我阅读的文章变为了 1+3+5。

现在,我要读的文章就从一开始的一篇主题文章变为了共计 8 篇文章,获取了 8 倍的信息。如果此时我的问题已经得到了解决,那么我就可以对这些信息进行收拢和汇总,达成我的目标。如果此时问题没有得到解决,则可以继续进行广度优先遍历,进行进一步的挖掘。

此外,如果到了某一层发现不再有相关的文章可以查看,则可以退回到搜索引擎,从第二篇开始重新进行主题级别的深度优先遍历。

作者 · 广度优先遍历

当我完成了当前主题的研究时,此时我仍然保有 8 篇文章的链接。窗口依然没有关闭,此时我会进行作者级别的广度优先遍历。

我会从当前的文章当中跳转到博客的归档页面或首页,从首页开始逐篇阅读下去,直到读完某篇博客。

基于之前开的 8 个不同的页面,可以进一步广度优先各博客主的文章,并在感兴趣的文章当中进行进一步的深度优先遍历,来查看更多的内容。

长此以往,你会发现,自己要看的文章越来越多。当然,你也可以收集到越来越多的信息。

使用 Sheetjs 将 JSON Array 转化为 Excel

使用 Sheetjs 将 JSON Array 转化为 Excel

使用 node-excel-stream 来按行处理 Excel 数据 中,我提到,如果你希望简单的完成 Excel 的读取和处理,那么 node-excel-stream 是个不错的选择。而反过来,如果你希望将 JSON Array 导出为 Excel,那么 Sheetjs 是个不错的选择。

注意

Sheetjs 和 exceljs 不同,区分了商业版和社区版。我们这里使用的是社区版 Sheetjs CE

用法

使用 Sheetjs 对数据进行导出时,你只需要调用 XLSX 方法当中的 json_to_sheet ,就可以将你的 JSON Array 变为一个 worksheet,接下来只需要将其放入一个新的 workbook 当中,并导出为文件,就可以完成 JS 数据导出为 Excel。

const XLSX = require("xlsx");

const data = [
  {
    ...
  },
  ...
]

const worksheet = XLSX.utils.json_to_sheet(data);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "sheetNameIsFirst");
XLSX.writeFile(workbook, "output.xlsx");
使用 node-excel-stream 来按行处理 Excel 数据

使用 node-excel-stream 来按行处理 Excel 数据

数据分析是一个非常常见的需求,而在实际的落地场景当中, Python 是使用最多的。不过我因为写了很久的前端,其实对于Python已经生疏了。当我开始启动项目时,就会选择执行 npm init 来初始化一个项目。既然如此,就试着使用 Node.js 来做数据分析。

在 Node.js 当中操作 Excel ,最好的便是 Exceljs。不过 ExcelJs 封装了大量的函数,对于绝大多数的数据分析场景来说,可能并不适用(也不一定,只是我比较喜欢用代码来描述逻辑,Excel 更多是一个导入导出)。

当明确了我只是需要一个简单的导入导出后,那么 node-excel-stream 就进入了我的视野。

读取 Excel 内容

和 Exceljs 不同,node-excel-stream 的封装相对简单,就是一个 Reader 和 Writer ,提供的方法也十分简单:读取文件、定义格式,按行处理内容;

需要注意的是,node-excel-stream 只支持 xlsx ,而不支持 xls,所以如果你用的是旧版,则需要重新保存成 xlsx 来进行处理。

let dataStream = fs.createReadStream('data.xlsx');
let reader = new ExcelReader(dataStream, {
    sheets: [{
        name: 'Users',
        rows: {
            headerRow: 1,
            allowedHeaders: [{
                name: 'User Name',
                key: 'userName'
            }, {
                name: 'Value',
                key: 'value',
                type: Number
            }]
        }
    }]
})
console.log('starting parse');
reader.eachRow((rowData, rowNum, sheetSchema) => {
    console.log(rowData);
})
.then(() => {
    console.log('done parsing');
});

写入 Excel 内容

写入时和读取时相比,稍微复杂一点,需要将所有的输入使用 Promise.all包裹起来

let writer = new ExcelWriter({
    sheets: [{
        name: 'Test Sheet',
        key: 'tests',
        headers: [{
            name: 'Test Name',
            key: 'name'
        }, {
            name: 'Test Coverage',
            key: 'testValue',
            default: 0
        }]
    }]
});
let dataPromises = inputs.map((input) => {
    // 'tests' is the key of the sheet. That is used
    // to add data to only the Test Sheet
    writer.addData('tests', input);
});
Promise.all(dataPromises)
.then(() => {
    return writer.save();
})
.then((stream) => {
    stream.pipe(fs.createWriteStream('data.xlsx'));
});

总结

如果你需要将 Excel 导入到 Js 当中进行处理,那么 node-excel-stream 是一个不错的选择。

warehouse — 一个简单易用的 JSON 数据库

warehouse — 一个简单易用的 JSON 数据库

在 Hexo 的 Github 组织下,有一个不明显,但却很有用的仓库 —— warehouse。

warehouse 是一个 JSON 数据库,基于 JSON 实现了各种类似于 SQL 的查询,可以帮助我们基于一个 JSON 文件来进行查询。在 Hexo 的静态生成过程中,warehouse 帮了大忙。

用官方的话来说,warehouse 就是 A JSON database with Models, Schemas, and a flexible querying interface.

在实际使用上,warehouse 确实如他所说的那边方便(虽然某些方法没有,但依然不影响他的使用很方便)。

Example

比如,如下代码就定义了 一个 Post 模型和对应的表。并实现了在这个表中插入一个新的数据。

var Database = require('warehouse');
var db = new Database();

var Post = db.model('posts', {
  title: String,
  created: {type: Date, default: Date.now}
});

Post.insert({
  title: 'Hello world'
}).then(function(post){
  console.log(post);
});

如果你需要将这些数据保存为一个单独的文件,只需要修改初始化的参数,并执行 save 方法,就可以将 JSON 导出到指定的文件中

var db = new Database({
  path: "./test.json", // 将数据存储在 test.json 当中
});
db.save();

类似的,如果数据已经构建好了,也只需要执行 load 方法,就可以加载数据。

var db = new Database({
  path: "./test.json", // 将数据存储在 test.json 当中
});
db.load();

场景

如果你希望在内存当中对于 JSON 有一个更好的操作方式,那么 warehouse 是个不错的选择,不需要另外单独安装数据库,就可以实现类似于数据库的查询方式,体验还是非常好的。

如果你想了解更多,可以查看

如何判断一个颜色是什么颜色?

如何判断一个颜色是什么颜色?

当你看到这个题目的时候,你可能会有点迷惑:“一个颜色是什么颜色”,这个问题好无厘头。但如果我换个用法 ,你可能就能明白 — 人类是如何辨别出一个颜色是红色而不是绿色?

回想小时候,大家应该都听说过 —— 三原色。不同的人可能记得不同,有的人记得是红绿蓝(色光三原色),也有人记得是红青黄(美术三原色)。结果不一样,但并不影响。两种三原色都告诉你了 —— 一个颜色是可以由另外三种颜色组合而成。

这意味着,每一个颜色都对应着三个坐标。他们是 RGB 也好,还是其他也好,都是通过三个颜色的色码来确认是哪个具体的颜色的。我们的显示器也是如此制造的。

但三原色有个问题 —— 变量太多。假设我们在每个维度分 3 个不同的结果,三原色可以拼出 27 种不同的组合。如果我们在每个维度分成 10 阶,这个结果就是 1000 个不同的维度。按照 RGB的 0 ~ 255 ,一共 256 阶,则一共可以形成 16,777,216 个组合。如果你想要构建出一组用于判断的规则,就十分的困难。

因此,换一个坐标系会是更好的办法 —— 试试 HSL 描述方法。

HSL 是将 RGB 三维坐标转换为色相、饱和度、亮度(英语:Hue, Saturation, Lightness)组成的新维度坐标。

当我们变为新的坐标系后,我们定义颜色的坐标就从过去的三个维度,变为了只需要色相(Hue)这一个坐标就可以定位的坐标。毕竟,如果一个蓝色不饱和饱和,都不影响他是个蓝色;同样的,一个蓝色的亮度不高,但依然是蓝色。

通过从 RGB 坐标系转变为 HSL 坐标系,我们就将过去的 16,777,216 个组合简化为 360 阶。从过去的三维坐标系,变为了全新的一维坐标系。

这样我们就可以十分简单的来细分我们的不同的颜色,更好的来编写规则。比如Hue 在 15 ~ 45 时为橙色;在45 ~ 75 时为黄色;在 75 ~105 时为绿色等等。

在我们写代码的时候也会更加简单,我们只需要计算出具体的 Hue 的值,就可以得出对应的颜色的名字。

RGB to HSL 算法

如下算法来自 Wikipedia

https://zh.wikipedia.org/wiki/HSL%E5%92%8CHSV%E8%89%B2%E5%BD%A9%E7%A9%BA%E9%97%B4

设 (rgb)分别是一个颜色的红、绿和蓝坐标,它们的值是在0到1之间的实数。设max等价于rgb中的最大者。设min等于这些值中的最小者。要找到在HSL空间中的 (hsl)值,这里的h ∈ [0, 360)是角度的色相角,而sl ∈ [0,1]是饱和度和亮度,计算为:h={\begin{cases}0^{\circ }&{\mbox{if }}max=min\\60^{\circ }\times {\frac  {g-b}{max-min}}+0^{\circ },&{\mbox{if }}max=r{\mbox{ and }}g\geq b\\60^{\circ }\times {\frac  {g-b}{max-min}}+360^{\circ },&{\mbox{if }}max=r{\mbox{ and }}g<b\\60^{\circ }\times {\frac  {b-r}{max-min}}+120^{\circ },&{\mbox{if }}max=g\\60^{\circ }\times {\frac  {r-g}{max-min}}+240^{\circ },&{\mbox{if }}max=b\end{cases}}

s={\begin{cases}0&{\mbox{if }}l=0{\mbox{ or }}max=min\\{\frac  {max-min}{max+min}}={\frac  {max-min}{2l}},&{\mbox{if }}0<l\leq {\frac  {1}{2}}\\{\frac  {max-min}{2-(max+min)}}={\frac  {max-min}{2-2l}},&{\mbox{if }}l>{\frac  {1}{2}}\end{cases}}”></p>



<p><img decoding=

h的值通常规范化到位于0到360°之间。而h = 0用于max = min的(定义为灰色)时候而不是留下h未定义。

RGB to HSL Sample Code

function rgbToHsl(r, g, b) {
  r /= 255, g /= 255, b /= 255;

  var max = Math.max(r, g, b),
    min = Math.min(r, g, b);
  var h, s, l = (max + min) / 2;

  if (max == min) {
    h = s = 0; // achromatic
  } else {
    var d = max - min;
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

    switch (max) {
      case r:
        h = (g - b) / d + (g < b ? 6 : 0);
        break;
      case g:
        h = (b - r) / d + 2;
        break;
      case b:
        h = (r - g) / d + 4;
        break;
    }

    h /= 6;
  }

  return [h, s, l];
}

延展阅读

https://www.december.com/html/spec/colorterms.html