はてだBlog(仮称)

私的なブログど真ん中のつもりでしたが、気づけばWebサイト系のアプリケーション開発周りで感じたこと寄りの自分メモなどをつれづれ述べています。2020年6月現在、Elasticsearch、pandas、CMSなどに関する話題が多めです。...ですが、だんだんとより私的なプログラムのスニペット置き場になりつつあります。ブログで述べている内容は所属組織で販売している製品などに関するものではなく、また所属する組織の見解を代表するものではありません。

自作の照合型ソートのスニペット例(JavaScriptでもmapやreduce、filter(手習いメモ) その4)

JavaScriptのmapやreduceは実用言語っぽい挙動で自分のようなぬる者にはありがたいよね〜のシリーズの第4弾です。

といいつつ、ある素材について、いざやってみるとfilterやreduceはおろか、メインロジック部分あたりではmapさえも使わなかったので、実際は、filterやreduceでおしゃれにコーディングできそうな雰囲気があるテーマについて、筆者の棋力ではそうはならなかったけど、そこそこスニペットとして面白かったので、公開してみました...という読み替えでお願いします。

とりあつかっているもの

  1. 漢字表記とカナ読みの固有名詞的なワードの組み合わせがあり、カナでない部分に読みを当てたトークンを生成
  2. 自作の照合型ソートの例

1がこりゃ面白いかもと思って始めたものの力技(というかナイーブな例)になってしまったので、記事にするには不足かなと思って、2も対応してみましたが、手グセで、2の方もナイーブな例となりました。 (ですが、書捨てるには惜しい気がしたので自分メモとして残しています。)

1. 漢字表記とカナ読みの固有名詞的なワードの組み合わせがあり、カナでない部分に読みを当てたトークンを生成

コード例

'use strict';

const a = 'ブラックJARKSニ世露死苦メカドッグ'.split('');
const bStr = 'ブラックジャックスニヨロシクメカドッグ';
const k = 0x30A1;
const kana = [...Array(92).keys()].map(i => String.fromCodePoint(k + i));
//const hiragana = [...Array(86).keys()].map(i => String.fromCodePoint(0x3041 + i));
console.log(kana);
const isKana = c => kana.includes(c);

const tokenize = a => {
    let c = a.shift();
    let p = c;
    const s = [p];
    while (a.length > 0) {
        c = a.shift();
        s.push(
            (isKana(c) && !isKana(p))
                || (!isKana(c) && isKana(p))
                ? ',' + c
                : c
        );
        p = c;
    }
    return s.join('').split(',');
};

const tokens = tokenize(a);

const getReadingForm = (tokens, bStr) => {
    const k2k = {};
    let str = bStr;
    for (let i = 0; i < tokens.length; i++) {
        const t = tokens[i];
        const kanaTknStsPos = str.indexOf(t);
        if (kanaTknStsPos < 0) {
            continue;
        }
        if (kanaTknStsPos === 0) {
            str = str.slice(t.length);
            continue;
        }
        const kanjiYomi = str.slice(0, kanaTknStsPos);
        k2k[tokens[i - 1]] = kanjiYomi;
        str = str.slice(kanaTknStsPos + t.length);
    }
    return k2k;
}

console.log(getReadingForm(tokens, bStr));


実行結果

{ JACKS: 'ジャックス', '世露死苦': 'ヨロシク' }

漢字と読み(例では変数 aとbStr)を前の方から比較して、同じカナが現れるまでは漢字(やアルファベットなど)と読みのペアとみなして、走査するイメージです。

ある前提のもと、diffっぽいことをナイーブなやり方で実施するイメージでしょうか。

2. 自作の照合型ソートの例

実際は難しいことはしておらず、Array.sort関数に、照合表で勝ち負けを参照しながら、並びを判定する関数を引き渡しして実現します。

'use strict';

const collationfunc = (a, b) => {
    const co = [...'abcdefghijklmnopqrstuvwxy'].reverse();  //照合用の配列。zはあえて無し。
    console.log(co);
    const ia = co.findIndex(e => e === a);
    const ib = co.findIndex(e => e === b);
    //どちらも存在しない場合は昇順
    if (ia === -1 && ib === -1) return a > b ? 1 : -1;
    //一方が存在しなければ、もう一方の存在する方の勝ち
    if (ia === -1) return 1;
    if (ib === -1) return -1;
    //照合の優先度が高い方が勝ち
    if (ia > ib) return 1;
    if (ia < ib) return -1;
};

const sorted = ['a', 'b', 'g', 'd', 'z', 'zzzz', 'f'].sort(collationfunc);

console.log(sorted);

/*

↓ 期待値イメージ

zをのぞく1文字アルファベットは降順。それ以外(zとzzzz)は最後尾となりこの2つの間はアルファベットの昇順。
[
 'g','f','d','b','a','z','zzzz'
]
*/