2015-06-16 24 views
5

Bardzo podoba mi się funkcjonalny styl programowania korzystania z mapy tablic do tworzenia tablicy obiektów z innej tablicy obiektów.Czy mogę ustawić klucze tablicy za pomocą funkcji tablicowych, takich jak array_map

$newObjects = array_map(
    function($oldObject) { 
    return new NewObject($oldObject); 
    }, 
    $oldObjects 
); 

Który wszystko działa dobrze, ale naprawdę chciałbym móc ustawić indeksy tablicy tak, że są identyfikatory oryginalnych obiektów dla łatwiejszego wyszukiwania i pobierania z tablicy, ale nie mogę myśleć, jak zrób to inne, co nie jest tak eleganckie.

$newObjects = array(); 
foreach ($oldObjects as $oldObject) { 
    $newObjects[$oldObject->getId()] = new NewObject($oldObject); 
} 

Czy mogę to zrobić?

+0

Komentarz adwokata diabła: tyle, ile kocham mapować/zmniejszać/chodzić itp. Czasami "foreach" jest najbardziej prostym, czytelnym rozwiązaniem :) –

+0

Tak, zgadzam się, konie na kursy i tak dalej. Spojrzenie na sugestię poniżej foreach ma o wiele więcej, jeśli chodzi o styl i czytelność. –

Odpowiedz

1

Co zrobić, jeśli używasz array_walk i tymczasowej tablicy z nowymi indeksami.

$array = ['A', 'B', 'C', 'D']; 
    $reIndexedTemp = []; 

    array_walk(
     $array, 
     function ($item, $key) use (&$reIndexedTemp) { 
      // here you can have your logic to assemble your new index 
      $reIndexedTemp[$key + 100] = $item; 
     } 
    ); 

    //$array = $reIndexedTemp; 

    var_dump($array, $reIndexedTemp); 

wyjścia (bez komentowanej linii):

array(4) { 
    [0] => 
    string(1) "A" 
    [1] => 
    string(1) "B" 
    [2] => 
    string(1) "C" 
    [3] => 
    string(1) "D" 
} 
array(4) { 
    [100] => 
    string(1) "A" 
    [101] => 
    string(1) "B" 
    [102] => 
    string(1) "C" 
    [103] => 
    string(1) "D" 
} 
+0

Hmm, myślę, że to mniej eleganckie! Nie chciałem korzystać z tymczasowej tablicy. Również klucz $ jest tylko oryginalnym kluczem, który nie jest uczciwy. –

+0

Nie jestem fanem tablicy temp :), ale wszystkie te funkcje tablicowe, o których mogłem pomyśleć, są przekazywane z indeksów tablicy z oczywistych powodów. A manipulowanie jednym środkiem przetwarzania samej tablicy nie wydaje się dobrym pomysłem. jeśli w ogóle nie potrzebujesz klucza z oryginalnej tablicy, możesz zignorować metodę array_walk i zachować tablicę array_map, ale obawiam się, że tymczasowa tablica nadal będzie wymagana! – Ali

+1

To nie jest tablica tymczasowa. Przechowuje dane wyjściowe, których potrzebujesz. Niestety 'array_walk()' modyfikuje tablicę, którą otrzymuje jako argument i nie zwraca żadnej użytecznej wartości.To nie może być stosowany bezpośrednio w funkcjonalnym stylu programowania :-(Jeśli trzeba użyć tego przepływ przetwarzania w kilku miejscach zastanowić owijania powyższy kod w funkcji, która zwraca tablicę „tymczasowy” (i spełnić swoje pragnienia funkcjonalnym stylu programowania.) – axiac

0

Rozglądając - Looking for array_map equivalent to work on keys in associative arrays

sugeruje to może pracować przy użyciu array_combine

więc myślę, że byłoby

$newObjects = array_combine(
    array_map(
    function($oldObject) { 
     return $oldObject->getId(); 
    }, 
    $oldObjects 
), 
    array_map(
    function($oldObject) { 
     return new NewObject($oldObject); 
    }, 
    $oldObjects 
) 
); 

Hmm chyba najlepszy, tylko po tej stronie przesadzone, ale na pewno o wiele bardziej skomplikowane niż foreach

+0

Snap! Rodzaj ... właśnie zobaczyłem Twój post po złożyłam moje. –

1

myślę, że foreach jest prawdopodobnie najbardziej czytelnym rozwiązaniem w tym przypadku, ale można użyć array_map() z array_combine() aby osiągnąć to, co chcieć. Coś jak:

// empty array to store the old object ids 
$ids = []; 

// map over old objects, inheriting $id 
// from parent scope by reference 
$objs = array_map(function($oldObject) use (&$ids) { 
    $ids[] = $oldObject->getId(); 
    return new NewObject($oldObject); 
}, $oldObjects); 

// combine id and object arrays 
$newObjects = array_combine($ids, $objs); 

nadzieję, że to pomaga :)

+0

Ach tak, że jest to nieco schludniej niż moje. Chociaż z jakiegoś powodu nie podoba mi tablicę zewnętrznego (mam irracjonalną niechęć obiekty przekazywane przez referencję!) –

+0

Haha, dość fair! to wygląda nieco gnarly porządku. Inne języki „funkcjonalny” zrobić to samo o wiele bardziej przejrzysty. PHP nie jest najładniejszy język Chyba, ale wciąż go kocham ... prawo ?? –

2

To jest - array_reduce() jest dokładnie to, czego potrzebujesz:

class Bar 
{ 
     protected $id; 

     public function __construct($id) 
     { 
       $this->id = $id; 
     } 

     public function getId() 
     { 
       return $this->id; 
     } 
} 

class Foo 
{ 
     protected $bar; 

     public function __construct(Bar $bar) 
     { 
       $this->bar = $bar; 
     } 
} 

$oldObjects = [new Bar('x'), new Bar('y'), new Bar('z')]; 

$newObjects = array_reduce($oldObjects, function($current, Bar $obj) { 
     $current[$obj->getId()] = new Foo($obj); 
     return $current; 
}, []); 

to zrobi wszystko na miejscu, bez konieczności wydać na dodatkową pamięć tablice takie jak dla array_combine()

Sugerowałbym jednak użycie takich konstrukcji, gdy są one niezbędne. Używanie tego tylko dlatego, że "wygląda lepiej" może nie być dobrym pomysłem - zwykłe pętle są w większości przypadków po prostu bardziej czytelne.

+0

Hmm, ciekawe. Trzeba spojrzeć trochę bardziej na tym, by właściwie się jak to działa (nigdy nie używane array_reduce dużo). zgadzam ve Wiele na ten temat niekoniecznie jest najlepszym podejściem i na zasadzie równowagi, myślę, że albo foreach albo opcje array_combine zapewniają najlepszą równowagę, czytelność i elegancję. Jest to bardziej ćwiczenia w zrozumieniu niż domagają się znaleźć funkcjonalne podejście, które jest lepsze niż foreach jednego (choć byłoby miło) –

+0

W samym dnie wszystkich tych opcji sprowadzają się do pętli, więc z tego, że to możliwe żeby ukryć to pod maską –