2017-03-15 3 views
3

Laravel Collection 클래스에 몇 가지 문제가 있습니다.복잡한 Laravel 컬렉션

것은 내가 할 노력하고있어 무엇 :

  • 내가 사이트가 "진행자"를 가지고있는 다중 사이트 해결책을 가지고 있습니다. 때로는 하나의 facilitator가 여러 사이트에 나타나기도합니다.
  • 메인 페이지에 모든 촉진자와 웹 사이트를 나열하고 싶지만 여러 사용자가 필요하지는 않습니다.

그래서 내가 현재 할 것입니다 :

  • 가 진행자를 가져옵니다.
  • 컬렉션을 사용하여 촉진자를 모으고 unique('name')을 사용하십시오.

이 기능을 사용하면 고유 한 촉진자를 얻을 수 있지만 감지 한 첫 번째 사람을 선택하고 다른 사람을 삭제합니다. unique()

Collection { 
    #items: array:3 [ 
    0 => array:2 [ 
     "name" => "John" 
     "site" => "Example" 
    ] 
    1 => array:2 [ 
     "name" => "Martin" 
     "site" => "Another" 
    ] 
    2 => array:2 [ 
     "name" => "John" 
     "site" => "Another" 
    ] 
    ] 
} 

내가 얻을 것 :

그래서 내가이 컬렉션이 말할 수

Collection { 
    #items: array:3 [ 
    0 => array:2 [ 
     "name" => "John" 
     "site" => "Example" 
    ] 
    1 => array:2 [ 
     "name" => "Martin" 
     "site" => "Another" 
    ] 
    ] 
} 

을 그리고 이것은 내가 얻고 싶은 것입니다 :

Collection { 
    #items: array:3 [ 
    0 => array:2 [ 
     "name" => "John" 
     "site" => ["Example", "Another"] 
    ] 
    1 => array:2 [ 
     "name" => "Martin" 
     "site" => "Another" 
    ] 
    ] 
} 

누구나 Laravel의 컬렉션 클래스로 이것을 어떻게 달성 할 수 있었는지 알 수 있습니까? 그것은 그에게 반복, 수집 내부에 2 차원 배열을 줄 것이다 있도록

+0

왜 'Group_concat'을 사용하지 않습니까? 이렇게하면 문제가 해결 될 수 있습니다. – Manish

+0

사이트가 DB 수준에서 사용자에게 할당되지 않았습니다. 모든 사이트를 반복하고, facilitator를 찾은 다음 facilitator 객체에 사이트 이름을 추가합니다. 나는이 컬렉션을 가지고 정말로해야 할 것이다. 기본적으로 내가하려는 일은 : 고유하지만 하나의 키를 병합합니다. –

+0

'GroupBy'를 사용해보십시오. 다음은 그 예입니다. 이것은 당신을 도울 수 있습니다. https://laravel.com/docs/5.4/collections#method-groupby – Manish

답변

3

컬렉션과 함께 붙어있는 경우 항상 reduce이 무기고에서 강력한 도구임을 기억하십시오.

내가, 내가 GROUPBY 작동합니다 함께 감소하여 생각 일 수 없었다 샘의 대답에

건물 ...

$sites = collect([ 
    ["name" => "John", "site" => "Example"], 
    ["name" => "Martin", "site" => "Another"], 
    ["name" => "John", "site" => "Another"], 
]); 

$sites->groupBy('name')->reduce(function ($result, $item) { 
    $result[] = [ 
    'name' => $item->first()['name'], 
    'sites' => $item->pluck('site')->toArray() 
    ]; 

    return $result; 
}, collect([]))->toArray(); 

그리고 콘솔에서

...

λ php artisan tinker                    
Psy Shell v0.8.2 (PHP 7.0.10 ÔÇö cli) by Justin Hileman           
>>> $sites = collect([                   
... ["name" => "John", "site" => "Example"],             
... ["name" => "Martin", "site" => "Another"],             
... ["name" => "John", "site" => "Another"],             
... ]);                       
=> Illuminate\Support\Collection {#698               
    all: [                      
     [                       
     "name" => "John",                  
     "site" => "Example",                  
     ],                       
     [                       
     "name" => "Martin",                  
     "site" => "Another",                  
     ],                       
     [                       
     "name" => "John",                  
     "site" => "Another",                  
     ],                       
    ],                       
    }                        
>>> $sites->groupBy('name')->reduce(function ($result, $item) {         
... $result[] = ['name' => $item->first()['name'], 'sites' => $item->pluck('site')->toArray()]; 
...                        
... return $result;                    
... }, collect([]))->toArray();                 
=> [                        
    [                       
     "name" => "John",                   
     "sites" => [                    
     "Example",                    
     "Another",                    
     ],                       
    ],                       
    [                       
     "name" => "Martin",                  
     "sites" => [                    
     "Another",                    
     ],                       
    ],                       
    ]                        

하나 주의해야 할 점은 질문에 하나의 사이트 만 있고 배열이 많은 경우 사이트가 단일 문자열을 반환해야한다는 것입니다. 위의 해결 방법은이를 제공하지 않습니다! 이것은 일관성이 없으며 나중에 사이트 키를 읽기만하고 조작하기가 더 어려워 지므로 항상 값이 하나라도 사이트 키 배열을 반환해야합니다.

그러나이 중요한 무언가를하는 경우 배열을 설정 뽑은를 사용하여 많은 사이트가있는 경우, 대신 확인할 수 있고 그렇지 않으면 당신은 다음과 같이 하나의 문자열로 설정할 수 있습니다 :

$sites->groupBy('name')->reduce(function ($result, $item) { 
    $result[] = [ 
    'name' => $item->first()['name'], 
    'sites' => $item->pluck('site')->count() > 1 ? $item->pluck('site') : $item->first()['site'] 
    ]; 

    return $result; 
}, collect([]))->toArray(); 

그러면 ...

[       
    [      
    "name" => "John",  
    "sites" => [   
     "Example",   
     "Another",   
    ],     
    ],      
    [      
    "name" => "Martin", 
    "sites" => "Another", 
    ],      
]       
+1

Perfect! 그게 내가하려는 일이야. reduce 메소드를 더 자세히 살펴 보겠습니다. 매우 강력한 메소드처럼 보입니다. 감사합니다 –

+0

좋아요! 그래, 당신은 실질적으로 감소와 함께 모든 수집 방법을 재 구현할 수 있습니다. 콜렉션 작업에 대해 더 자세히 알고 싶다면이 리소스를 적극 권장합니다. https://adamwathan.me/refactoring-to-collections/ - 행복한 코딩! – haakym

+1

@haakym 훌륭한 답변입니다. 당신의 대답은 정말로 감사 할 만합니다. 계속하십시오. 신의 축복이있어. – Manish

0

당신이 $ 수집 가정, 정확히 당신이 원하는 것을 얻기 위해 체인에 의해 그것을 할 수는 기본 모음을 이름으로

$collection->groupBy('name')->map(function($facilitators) { 
    return ['name' => $facilitators->first()['name'], 'site' => $facilitators->pluck('site')->toArray()]; 
})->values()->toArray(); 

우선 그룹입니다 이름은 공통적이므로 첫 번째 요소에서 가져온 다음 모든 요소 추출 사이트에서 가져 와서 배열로 변환하면 flatMap을 사용하면 단일 레벨 중첩이됩니다.

+0

이 코드를 실행 했습니까? 그것은 나를 위해 작동하지 않았다. '$ facilitators-> first() -> name'은'first()'메쏘드가 배열을 반환하고 당신이 객체처럼 그것에 접근하려한다고 생각할 때 이름에 접근 할 수 없다는 오류를 리턴합니다. – haakym

+1

@haakym 고마워! 그 책을 확실히 읽으려고합니다 :) –

+0

toArray()를 제외한 배열의 모든 메소드가 반환되지 않습니다. all()은 컬렉션의 첫 번째 항목을 먼저 반환하고 해당 항목은 객체라고 생각합니다. 항목 자체는 배열입니다. 조금 수정해야하지만 질문에 표시된 덤프에 중첩 된 컬렉션이있는 것 같습니다 –