見出し画像

あると便利かもしれないスニペット集2

あると便利かもしれないものたち

みなさんこんにちは、ALH開発事業部のREIYAです。

かゆいところに手が届くような便利スニペットをまとめてみました。
前回分もよろしくお願いします。

今回書いたもの


JS

Ajax

「あじゃっくす」と呼んでいます。ただしくは「えいじゃっくす」

// XXX こんなの環境変数でやってね!!!!これだめだからね!!!!
export const url = window.location.host == 'localhost:8080'
  ? 'http://localhost:3000/'
  : 'https://商用.com/なんとかapi/';

export const Ajax = {
  post(url, data, func, efunc) {
    const method = "POST";
    const headers = {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'x-custom-header': 'some value',
    };
    const request = {
      'data': data
    };
    console.debug(request);
    const body = JSON.stringify(request);
    fetch(url, {method, headers, body})
      .then(res => {
        // 400 <= res.status && res.status <= 499
        // でもよい
        if ([400, 401, 403].some(v => res.status == v)) {
          if (efunc) {
            efunc(res)
          };
          return;
        }
        if (!res.ok) {
          throw new Error(res.statusText);
        }
        return res.json();
      })
      .then(v => {
        console.debug(v);
        // ここからはAPIレスポンス形による
        if (v.api_status_core === '0') {
          func(v);
        } else {
          efunc(v);
        }
      })
      .catch(e => {
        console.error(e);
      });
  },
  // GET ...
};

現在日時

//yyyyMMdd
const now = new Date().toISOString().split("T")[0].replaceAll("-", "");

Date.now() // ミリ秒

sleep

const sleep = (ms) => new Promise(r => setTimeout(r, ms));

async () => {
  console.debug("start")
  await sleep(1000)
  console.debug("end")
}

連番生成

先頭が「[」で始まるので、前の行にセミコロンが必須です。

[...Array(100)].map((_,  i) => i).forEach(...); // 0-indexed
[...Array(100).keys()].forEach(...); // 0-indexed

forどうしても書きたくない人向け

let a = 1
for (let i = 0; i < 10; ++i) {
  a *= 2
}
console.log(a) // 1024

この程度(前回の結果を次に使う漸化式型、動的計画法)であれば以下でよい

console.log([...Array(10).keys()].reduce((x, y) => x * 2, 1))

こうでもいい。a *= 2のが文字数少ないですがなんとなくビット演算したかった

for(a=1,i=0;i<10;a<<=1,++i==10&&console.log(a));

文字列→数値へ変換

二重ビット否定で数値になる。数値変換できない文字の時は0になる(はず)

let str = "12345";
let number = ~~str;

const toint = str => ~~str;

jQueryもどき

HTMLいじる系です

const $$ = document;
const $ = v => v.startsWith('#') ? $$.getElementById(v.slice(1)) : $$.querySelector(v);
const _$ = (e = "div") => $$.createElement(e);
const DOM = str => new DOMParser().parseFromString(str, "text/html").body.firstElementChild;
const attr = (e, att) => Object.entries(att).map(([k, v]) => e[k] = v);
const css = (e, sty) => Object.entries(sty).map(([k, v]) => e.style[k] = v);
const event = (e, f, v = 'click') => e.addEventListener(v, f);

FFT

JSである必要は全くないですが、過去に理解のために書いたことがあるのでせっかくだから置いておきますね。
参考:

参考記事で勉強した際の名残でナイーブ実装のDFTもありますので、せっかくだから実行時間比較してみました。

なおデータ数が2冪じゃないとバグるので未完成ではあります。
wandboxでのpermlink共有

投入データ

dat = [10,10,12,13,15,13,12,10, 10,10,12,13,15,13,12,10];
[...Array(9).keys()].forEach(_ => dat = [...dat, ...dat]);
console.log(dat)

複素数用

exp = theta => [Math.cos(theta), Math.sin(theta)]
add = ([x1, y1], [x2, y2]) => [x1 + x2, y1 + y2]
sub = ([x1, y1], [x2, y2]) => [x1 - x2, y1 - y2]
mul = ([x1, y1], [x2, y2]) => [x1 * x2 - y1 * y2, x1 * y2 + y1 * x2]

DFT

dftc = (c, T) => [...Array(c.length).keys()]
.map(i => c.map((cn, n) => mul(cn, exp(T * n * i))).reduce(add, [0, 0]));
DFT = f => dftc(f, -2 * Math.PI / f.length)
IDFT = F => dftc(F, 2 * Math.PI / F.length).map(([r, i]) => [r / F.length, i / F.length])
start = Date.now()
discrete_tx = DFT(dat.map(r => [r, 0]));
discrete_rev = IDFT(discrete_tx).map(([r]) => r).map(Math.round);
console.assert(JSON.stringify(dat) === JSON.stringify(discrete_rev), {dat, discrete_rev});
console.log(discrete_tx)
console.log(discrete_rev)
console.log(Date.now() - start)
[
  [ 97280, 0 ],
  [ -4.778399897986674e-12, 9.47056669198254e-13 ],
  [ 3.907985046680551e-14, -2.0174036052811317e-12 ],
中略
]
[
  10, 10, 12, 13, 15, 13, 12, 10, 10, 10, 12, 13,
中略
]
13480

FFT
※ビット反転のとこでなにも考えずに$${log_2N}$$してるからだめです。バタフライ部分は大丈夫

function fftc(c, T, N) {
    const rec = c.map((_, n) => c[[...Array(Math.log2(N)).keys()].reduce((x, y) => (x << 1) | ((n >>> y) & 1), 0)]);
    for (let Nh = 1; Nh < N; Nh *= 2) {
        T /= 2;
        for (let s = 0; s < N; s += Nh * 2) {
            for (let i = 0; i < Nh; i++) {
                const l = rec[s + i], re = mul(rec[s + i + Nh], exp(T * i));
                [rec[s + i], rec[s + i + Nh]] = [add(l, re), sub(l, re)];
            }
        }
    }
    return rec;
}
FFT = f => fftc(f, -2 * Math.PI, f.length)
IFFT = F => fftc(F, 2 * Math.PI, F.length).map(([r, i]) => [r / F.length, i / F.length])
start = Date.now()
FFT_tx = FFT(dat.map(r => [r, 0]));
FFT_rev = IFFT(FFT_tx).map(([r]) => r).map(Math.round);
console.assert(JSON.stringify(dat) === JSON.stringify(FFT_rev), {dat, FFT_rev});
console.log(FFT_tx)
console.log(FFT_rev)
console.log(Date.now() - start)
[
  [ 97280, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ],
  [ 0, 0 ],     [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ],
中略
]
[
  10, 10, 12, 13, 15, 13, 12, 10, 10, 10, 12, 13,
中略
]
53

DFT 13480msに対しFFT 53msですね、こう見ると威力を感じます。logは偉大。
最初の方でデータ数16個を$${2^9}$$倍していますが、10乗あたりからwandboxではメモリ足りなくなったからです。

だれか2冪丸め版作ってください。

React

ReactもJSじゃないか!というツッコミは受け付けていません。

ちなみに分割代入とスプレッド構文が入り乱れるのでReduxはあまり好きではないです...。

useStateコピー注意やつ

const [arr, setArr] = useState<[]>([]);

let tmp = [...arr] // ディープコピーすること!
// tmpに操作
setArr(tmp)

以下がダメ例。昔ずっと悩んでたstate更新されない問題はだいたいこれが原因でした。ほんまこいつ...

let tmp = arr
// tmpに操作
setArr(tmp)

メモ化

お手軽の高速になる(!?)やつ。仮装DOMとの差分レンダリングを操作しているイメージ。なるべく変えるなよって感じ。

const isOpen = useMemo(() => {
  let st: boolean = false;
  // なにやら処理
  return st;
}, [watchArg]);

副作用管理

useEffectです。hookって過激派多いので深くは触れないでおきますね

const [cnt, setCnt] = useState(0);
useEffect(() => {
  console.log(`new count is ${cnt}`);
}, [cnt]);

オレオレコンポーネント

なんかこう、カッコが多いのであんま好きじゃないです。

type Props = {
  name: string;
  value: string;
  func: (e: React.ChangeEvent<HTMLInputElement>) => void;
};

const MyComponent: React.FC<Props> = (({name, value, func}) => {
  useEffect(() => {}, []);
  return (
    <div className={some}>
	  <div ...>
    </div>
  );
});

export default MyComponent;

axios

Reactじゃないですが、どうせみなさん一緒に使ってますよね?

import axios from "axios"

export function my_post(url, data) {
    const host = 'いいかんじに取得';
    // cookieにtoken、sessionStorageに値があるとする
    let token = document.cookie.split(";").map(v => v.trim()).filter(v => v.startsWith("token="))
    token = token.length === 0 ? "" : token[0].split("=")[1]
    const headers = {
        'Content-Type': 'application/json',
        'x-custome-header': sessionStorage.getItem("some value"),
        'x-custome-token': token
    }
    return axios.post(host + url, data, {headers: headers});
}

Rust

チェーン

Javaでいうstreamのようにiterのチェーンを。
forと一応比較しておく

fn main() {
  let list = vec!["test", "test"];
  let a: Vec<String> = list.iter()
    .filter(|&v| *v == "test")
    .inspect(|&v| println!("{}", *v))
    .map(|&v| v.to_string())
    .collect();
  for v in list.iter() {
      if *v == "test" {
          println!("{}", v);
      }
  }
  for v in 0..a.len() {
    println!("{}", v);
  }
}

フィボナッチ

行列累乗です。多倍長数値演算ライブラリrugを使用する版はこちらの記事で取り上げられています。FFTらしいので高速。

$$
\begin{pmatrix}
1 & 1 \\
1 & 0
\end{pmatrix}
\begin{pmatrix}
F_{n+1} \\ F_{n}
\end{pmatrix} =
\begin{pmatrix}
F_{n + 1} + F_{n}\\ F_{n+1}
\end{pmatrix}
\begin{pmatrix}
F_{n + 2} \\ F_{n+1}
\end{pmatrix}
$$

use std::io::stdin;

fn fib(n: i32) -> i32 {
    if n < 1 {
        return 0;
    }
    let mut mat: Vec<Vec<i32>> = vec![
        vec![1, 1],
        vec![1, 0],
    ];
    let factor: Vec<Vec<i32>> = vec![
        vec![1, 1],
        vec![1, 0],
    ];
    for _ in 1..n {
        let mut tmp = vec![
            vec![0, 0],
            vec![0, 0],
        ];
        tmp[0][0] = (
            mat[0][0].clone() * &factor[0][0]
        ) + (
            mat[0][1].clone() * &factor[1][0]
        );
        tmp[0][1] = (
            mat[0][0].clone() * &factor[0][1]
        ) + (
            mat[0][1].clone() * &factor[1][1]
        );
        tmp[1][0] = (
            mat[1][0].clone() * &factor[0][0]
        ) + (
            mat[1][1].clone() * &factor[1][0]
        );
        tmp[1][1] = (
            mat[1][0].clone() * &factor[0][1]
        ) + (
            mat[1][1].clone() * &factor[1][1]
        );
        mat = tmp;
    }
    return mat[0][1].clone();
}
fn input() -> i32 {
    let mut buf = String::new();
    stdin().read_line(&mut buf).unwrap();
    return buf.trim().parse().unwrap();
}
fn main() {
    let n: i32 = input();
    let res = fib(n);
    println!("{}", res);
}

C++

約数

いったい何が役立つのか全くわからず苦しまぎれ。
未ソートでの約数全列挙

#include <iostream>
#include <vector>
template <typename T> std::vector<T> divisors(T a) {
    std::vector<T> res;
    for (T i = 1; i * i <= a; ++i) {
        if (a % i != 0) continue;
        res.push_back(i);
        if (a / i != i) res.push_back(a / i);
    }
    return res;
}
int main() {
    int N;
    std::cin >> N;
    for (auto &&v : divisors(N)) {
        std::cout <<  v << std::endl;
    }
}

素因数分解

なんとなく書いておきます。

#include <iostream>
#include <map>
template <typename T> std::map<T, int> p_fact(T N) {
    std::map<T, int> P;
    for (T i = 2; i * i <= N; ++i) {
        while (N % i == 0) {
            ++P[i];
            N /= i;
        }
    }
    if (N > 1) ++P[N];
    return P;
}
int main() {
    int N;
    std::cin >> N;
    for (auto &&[k, v] : p_fact(N)) std::cout << k << ": " << v << std::endl;
}

FFT

jsで書いたのでせっかくですし。
ついでに畳み込みも作ってあるので載せときます。
こっちはちゃんと2冪丸めしてます。

#include <bits/stdc++.h>
using namespace std;
namespace FFT {
using real = double;
struct C {
    real x, y;
    C() : x(0), y(0){};
    C(real x, real y) : x(x), y(y){};
    inline C operator+(const C &c) const {
        return C(x + c.x, y + c.y);
    }
    inline C operator-(const C &c) const {
        return C(x - c.x, y - c.y);
    }
    inline C operator*(const C &c) const {
        return C(x * c.x - y * c.y, x * c.y + y * c.x);
    }
    inline C conj() const {
        return C(x, -y);
    }
};
const real PI = acosl(-1);
int base = 1;
vector<C> rts = {{0, 0}, {1, 0}};
vector<int> rev = {0, 1};
void ensure_base(int nbase) {
    if (nbase <= base) return;
    rev.resize(1 << nbase);
    rts.resize(1 << nbase);
    for (int i = 0; i < (1 << nbase); i++) {
        rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
    }
    while (base < nbase) {
        real angle = PI * 2.0 / (1 << (base + 1));
        for (int i = 1 << (base - 1); i < (1 << base); i++) {
            rts[i << 1] = rts[i];
            real angle_i = angle * (2 * i + 1 - (1 << base));
            rts[(i << 1) + 1] = C(cos(angle_i), sin(angle_i));
        }
        ++base;
    }
}
void fft(vector<C> &a, int n) {
    assert((n & (n - 1)) == 0);
    int zeros = __builtin_ctz(n);
    ensure_base(zeros);
    int shift = base - zeros;
    for (int i = 0; i < n; i++) {
        if (i < (rev[i] >> shift)) swap(a[i], a[rev[i] >> shift]);
    }
    for (int k = 1; k < n; k <<= 1) {
        for (int i = 0; i < n; i += 2 * k) {
            for (int j = 0; j < k; j++) {
                C z = a[i + j + k] * rts[j + k];
                a[i + j + k] = a[i + j] - z;
                a[i + j] = a[i + j] + z;
            }
        }
    }
}
} // namespace FFT

畳み込みと呼んでみる。
llround誤差あるので気になる場合はNTTすること

template <typename R>
vector<long long> convolution_fft(const vector<R> &a, const vector<R> &b) {
    using C = FFT::C;
    int need = (int)a.size() + (int)b.size() - 1, nbase = 1;
    while ((1 << nbase) < need) ++nbase;
    FFT::ensure_base(nbase);
    int sz = 1 << nbase;
    vector<C> fa(sz);
    for (int i = 0; i < sz; i++) {
        double x = i < (int)a.size() ? a[i] : 0;
        double y = i < (int)b.size() ? b[i] : 0;
        fa[i] = C(x, y);
    }
    FFT::fft(fa, sz);
    C r(0, -0.25 / (sz >> 1)), s(0, 1), t(0.5, 0);
    for (int i = 0; i <= (sz >> 1); i++) {
        int j = (sz - i) & (sz - 1);
        C z = (fa[j] * fa[j] - (fa[i] * fa[i]).conj()) * r;
        fa[j] = (fa[i] * fa[i] - (fa[j] * fa[j]).conj()) * r;
        fa[i] = z;
    }
    for (int i = 0; i < (sz >> 1); i++) {
        C A0 = (fa[i] + fa[i + (sz >> 1)]) * t;
        C A1 = (fa[i] - fa[i + (sz >> 1)]) * t * FFT::rts[(sz >> 1) + i];
        fa[i] = A0 + A1 * s;
    }
    FFT::fft(fa, sz >> 1);
    vector<long long> ret(need);
    for (int i = 0; i < need; i++) {
        ret[i] = llround(i & 1 ? fa[i >> 1].y : fa[i >> 1].x);
    }
    return ret;
}
int main() {
    vector<int> A = {1, 2, 3, 4, 5};
    vector<int> B = {2, 3, 5, 7, 11, 13};
    for (auto &&v : convolution_fft(A, B)) {
        cout << v << endl;
    }
}

おわり

前回同様統一感ないですが、どこかで使えることがあったらうれしいです。

ALHについて知る



↓ ↓ ↓ 採用サイトはこちら ↓ ↓ ↓


↓ ↓ ↓ コーポレートサイトはこちら ↓ ↓ ↓


↓ ↓ ↓ もっとALHについて知りたい? ↓ ↓ ↓