LoginSignup
20
20

More than 5 years have passed since last update.

[PHP, Ruby] ハッシュに対するいろいろなMap

Last updated at Posted at 2014-11-16

はじめに

PHPとRubyにはおおまかに以下のような用語の対応関係があります。

PHP Ruby
関数 メソッド
メソッド
数字添字配列 配列
連想配列 ハッシュ
stdClass
無名関数 ブロック
proc
lambda

実装

それぞれの言語で、以下の関数・メソッドを書いてみることにします。用語はRuby側に統一します。

  • ハッシュの各要素の に対してブロックを適用し、それらの返り値を集めた新しいハッシュを返す
  • ハッシュの各要素の キー に対してブロックを適用し、それらの返り値を集めた新しいハッシュを返す
  • ハッシュの各要素の 値とキー に対してブロックを適用し、それらの返り値を集めた新しいハッシュを返す

なお、Rubyは初心者です。

PHP

コード
<?php

function array_kmap(callable $func, array $arr) {
    return array_combine(array_map($func, array_keys($arr)), $arr);
}
function array_kvmap(callable $func, array $arr) {
    $new = array_map($func, array_keys($arr), $arr);
    return $new ? call_user_func_array('array_merge', $new) : $new;
}

$arr = [
    'k1' => 10,
    'k2' => 15,
    'k3' => 20,
];

print_r(array_map(function ($v) { return $v / 100.0; }, $arr));
print_r(array_kmap(function ($k) { return $k . 'a'; }, $arr));
print_r(array_kvmap(function ($k, $v) { return [$k . 'a' => $v / 100.0]; }, $arr));
結果
Array
(
    [k1] => 0.1
    [k2] => 0.15
    [k3] => 0.2
)
Array
(
    [k1a] => 10
    [k2a] => 15
    [k3a] => 20
)
Array
(
    [k1a] => 0.1
    [k2a] => 0.15
    [k3a] => 0.2
)

array_merge を引数なしでコールするとエラーが発生するために、空配列のチェックが必要になってしまうところが惜しいです。

Ruby

コード
class Hash
    def vmap
        map{|k, v| [k, (yield v)]}.to_h
    end
    def kmap
        map{|k, v| [(yield k), v]}.to_h
    end
    def kvmap
        map{|k, v| yield k, v}.to_h
    end
end

h = {
    'k1' => 10,
    'k2' => 15,
    'k3' => 20,
}

p h.vmap{|v| v / 100.0}
p h.kmap{|k| k + 'a'}
p h.kvmap{|k, v| [k + 'a', v / 100.0]}
結果
{"k1"=>0.1, "k2"=>0.15, "k3"=>0.2}
{"k1a"=>10, "k2a"=>15, "k3a"=>20}
{"k1a"=>0.1, "k2a"=>0.15, "k3a"=>0.2}

やはりRubyは美しいですね。コードが短い。標準クラスをすんなり拡張出来ちゃうあたりも優秀。

なお、Ruby2.0以前だと array.to_h が使えないので Hash[array] で代用します。ぶっちゃけ kvmap に関しては to_h 生やすだけなのでメソッド要らないかも…

あとがき

キーと値を両方使うとき、返り値を [k, v] とするか {k => v} とするかが共通の問題になりそうです。

  • Rubyは言語実装が [k, v] 型を想定しているのでこちらの方が優位です。
    (編集前は {k => v} 型だったので inject メソッド使ってました…)
  • PHPは [k, v] 型で実装すると…ちょっと無理矢理感出てしまいます。
あくまで関数型コーディングだ!(但しPHP5.5以降に限る)
function array_kvmap(callable $func, array $arr) {
    $new = array_map($func, array_keys($arr), $arr);
    return array_combine(array_column($new, 0), array_column($new, 1));
}
手続き型で妥協しました(でも多分一番速い)
function array_kvmap(callable $func, array $arr) {
    $new = [];
    foreach ($arr as $k => $v) {
        list($k, $v) = $func($k, $v);
        $new[$k] = $v; 
    }
    return $new;
}

コメント欄にてPythonのコードも投げつけてくれると多分喜びます。

20
20
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
20