web-dev-qa-db-ja.com

配列インターフェイスを持つコレクションのarray_map?

同じタイプのオブジェクトを格納するCollectionというクラスがあります。 Collectionは配列インターフェイスを実装します:IteratorArrayAccessSeekableIterator、およびCountable

Collectionオブジェクトを配列引数として array_map 関数に渡したいのですが。しかし、これはエラーで失敗します

PHP警告:array_map():引数#2は配列である必要があります

Collectionオブジェクトが配列として表示されるように、他の/より多くのインターフェイスを実装することでこれを実現できますか?

26
f1ames

array_map()関数は、配列引数としてTraversableをサポートしていないため、変換手順を実行する必要があります。

_array_map($fn, iterator_to_array($myCollection));
_

コレクションを2回繰り返し処理するだけでなく、後で使用されない配列も生成します。

もう1つの方法は、独自のマップ関数を作成することです。

_function map(callable $fn)
{
    $result = array();

    foreach ($this as $item) {
        $result[] = $fn($item);
    }

    return $result;
}
_

更新

ユースケースから判断すると、マップ操作の結果にさえ興味がないようです。したがって iterator_apply() を使用する方が理にかなっています。

_iterator_apply($myCollection, function($obj) {
    $obj->method1();
    $obj->method2();

    return true;
});
_
25
Ja͢ck

_array_map_は、名前が示すように、arraysを必要とします。結局、それは_iterator_map_と呼ばれるわけではありません。 ;)

潜在的に大きな一時配列を生成するiterator_to_array()を除いて、反復可能オブジェクトを_array_map_で動作させるトリックはありません。

Functional PHP ライブラリには、反復可能なコレクションで機能するmap実装があります。

7
deceze

notが、元の配列にマップされた関数である新しい配列の作成に興味がある場合は、foreachループを使用できます(Iteratorを実装しているため)。

foreach($item in $myCollection) {
    $item->method1();
    $item->method2();
}

実際にマップを使用したい場合は、独自に実装する必要があると思います。コレクションのメソッドにすることをお勧めします。例:

$mutatedCollection = $myCollection->map(function($item) { 
    /* do some stuff to $item */
    return $item;
});

あなたが本当にmapを使いたいのか、それともforeach

3
Chris M

私は次の解決策を思いつきました:

//lets say you have this iterator
$iterator = new ArrayIterator(array(1, 2, 3));

//and want to append the callback output to the following variable
$out = [];

//use iterator to apply the callback to every element of the iterator
iterator_apply(
    $iterator,
    function($iterator, &$out) {
        $current = $iterator->current();
        $out[] = $current*2;
        return true;
    },
    array($iterator, &$out) //arguments for the callback
);

print_r($out);

このようにして、次のようなアプローチの場合のように2回繰り返すことなく配列を生成できます。

$iterator = new ArrayIterator(array(1,2,3));
$array = iterator_to_array($iterator); //first iteration
$output = array_map(function() {}, $array); //second iteration

幸運を!

3

私はこの質問に遭遇しただけで、コレクションを配列にキャストして機能させることができました。

array_map($cb, (array) $collection);

免責事項元の質問の場合、これは適切なオプションではない可能性がありますが、この解決策で解決した問題を解決しようとしているときに質問を見つけました。可能/実行可能な場合は、カスタムイテレータマップを使用することをお勧めします。

別のオプションは次のようなことをすることです:

foreach($collection as &$item) {
    $item = $cb($item);
}

基になるコレクションを変更します。

0
Andrew Willis