2013-04-29 30 views
18

Tôi có một lớp được gọi là Collection lưu trữ các đối tượng cùng loại. Collection triển khai các giao diện mảng: Iterator, ArrayAccess, SeekableIteratorCountable.array_map trên bộ sưu tập có giao diện mảng?

Tôi muốn chuyển đối tượng Collection làm đối số mảng cho hàm array_map. Nhưng điều này không thành công với các lỗi

PHP Warning: array_map(): Đối số # 2 nên là một mảng

Tôi có thể đạt được điều này bằng cách thực hiện khác/nhiều giao diện, do đó Collection đối tượng được coi là mảng?

+3

cuộn chức năng collection_map của riêng bạn? – Adder

+0

@Adder Course Tôi có thể, nhưng bây giờ tôi đang tìm giải pháp nếu tôi có thể sử dụng Bộ sưu tập của tôi với funcs xây dựng php :) – f1ames

Trả lời

6

array_map muốn, như tên cho thấy, mảng. Nó không được gọi là iterator_map sau khi tất cả. ;)

Ngoài iterator_to_array(), tạo ra một mảng tạm thời có khả năng lớn, không có mẹo để làm cho các đối tượng có thể lặp lại hoạt động với array_map.

Thư viện Functional PHP có triển khai map hoạt động trên mọi bộ sưu tập có thể lặp lại.

+0

Việc triển khai bản đồ PHP chức năng không hiệu quả về bộ nhớ: kết quả được lưu trữ trong mảng. Tôi tìm thấy một thư viện tốt hơn: https://github.com/SuRaMoN/itertools Và một bài đăng trên blog giải thích cách bạn có thể tự xây dựng nó: http://www.a-basketful-of-papayas.net/2012/07/what -iterator-can-do-for-you.html –

+0

Aad, nói chung kết quả của một hàm bản đồ là một mảng * mới * - chi phí bộ nhớ là bẩm sinh cho cách tiếp cận và không đáng kể trong phần lớn các trường hợp sử dụng. –

+0

"Không có mẹo để làm cho các đối tượng có thể lặp lại hoạt động với' mảng_map'. " Bí quyết đó là 'iterator_to_array()'. –

19

Chức năng array_map() không hỗ trợ một Traversable như là đối số mảng của nó, do đó bạn sẽ phải thực hiện một bước chuyển đổi:

array_map($fn, iterator_to_array($myCollection)); 

Bên cạnh iterating qua bộ sưu tập hai lần, nó cũng mang lại một mảng đó sẽ không được sử dụng sau đó.

Một cách khác là để viết chức năng bản đồ của riêng bạn:

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

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

    return $result; 
} 

Cập nhật

Đánh giá bởi use-case của bạn có vẻ như rằng bạn thậm chí không quan tâm đến kết quả của hoạt động bản đồ ; do đó nó có ý nghĩa hơn để sử dụng iterator_apply().

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

    return true; 
}); 
+1

Điều này làm việc, nhưng có một hình phạt hiệu suất vì nó sẽ lặp lại trong bước iterator_to_array và nó sẽ lặp lại một lần nữa trong bước array_map. –

+1

@EelkevandenBos Tôi đưa ra hai giải pháp trong câu trả lời của tôi, sau này không trưng bày "hình phạt hiệu suất" này; bên cạnh đó, trong cả hai trường hợp thời gian chạy là O (n). –

2

tôi đã đưa ra các giải pháp sau đây:

//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); 

Bằng cách này, bạn có thể tạo một mảng mà không lặp lại hai lần như bạn sẽ đến với cách tiếp cận như:

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

Tốt may mắn!

3

Nếu bạn đang không phải quan tâm đến việc tạo mảng mới là hàm được ánh xạ trên mảng ban đầu, bạn chỉ có thể sử dụng vòng lặp foreach (vì bạn triển khai Iterator).

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

nếu bạn thực sự muốn sử dụng bản đồ, thì tôi nghĩ bạn sẽ phải thực hiện bản đồ của riêng mình.Tôi sẽ đề nghị làm cho nó một phương pháp trên Collection, ví dụ:

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

tôi sẽ tự hỏi mình nếu bạn thực sự muốn sử dụng map hoặc bạn có thực sự chỉ có nghĩa là foreach

Các vấn đề liên quan