简体   繁体   中英

How to merge elements in array of arrays with similar keys differing by one key value only

I am working with PHP and have an Array of Arrays that looks something like this:

Array(
    [0] => Array(
           [id]  =>1,
           [name]=>"edward",
           [asset]=>"somesong.mp3"
           ),
    [1] => Array(
           [id]  =>1,
           [name]=>"edward",
           [asset]=>"somemovie.mov"
           ),
    [2] => Array(
           [id]  =>2,
           [name]=>"sally",
           [asset]=>"anothersong.mp3"
           ),
    [3] => Array(
           [id]  =>2,
           [name]=>"sally",
           [asset]=>"anothermovie.mov"
           ),
...
)

As you can see, their are similarities between each element in the main array, only differing by the value of the [asset] key. I would like to merge the elements in the main array so that both values of each [asset] are kept in the new element, like this

FinalArray(
    [0] => Array(
           [id]  =>1,
           [name]=>"edward",
           [song]=>"somesong.mp3",
           [movie]=>"somemovie.mov"
           ),
    [1] => Array(
           [id]  =>2,
           [name]=>"sally",
           [song]=>"anothersong.mp3",
           [movie]=>"anothermovie.mov"
           )
...
)

I began to explore using a combination of inner and outer foreach() loops using the structure

// $person and $person02 are copies of the same array
foreach($person as $key=>$value){
    // grab an element in this loop
    $currElement=$person[$key];
    foreach($person2 as $key2=>$value2){
        $currElement2=$person2[$key2];
        // compare $currElement to $currElement2
        if($currElement['id']==$currElement2['id']){
            // determine if [asset] is an mp3 or mov
            $currAsset2=$currElement2['asset'];
            $currAsset =$currElement['asset'];

            $ext = substr(strrchr($currAsset,'.'),1)
            if($ext=='mp3'){ 
                // then we have a song and should store it
                $song=$currAsset['asset'];
                $movie=$currAsset2['asset'];
            }else{
                //  switch sides if you like
                $song=$currAsset2['asset'];
                $movie=$currAsset['asset'];
            }
        }

        // create a new array and add it to the result array
        $newArrEl = array(
            'id'   =>$currElement['id'],
            'name' =>$currElement['id'],
            'song' => $song,
            'movie' => $movie
        );
        $resultArray.push(); // add to final array
    }
}
}

The thing is, I explored a bunch of combination of php array functions and cannot seem to get it quite right. So I am hoping someone here on SO can also help me out with this. how can I get the original data to merge with like values into newer elements to be added to a final array?

Looks like your main identifier is the id, I would make an target array with id as keys, and iterate through the original array just once, like this:

<?php 

$original_array = array(
    array(
        'id' => 1,
        'name' => 'edwards',
        'asset' => "somesong.mp3"
    ),
    array(
        'id' => 1,
        'name' => 'edwards',
        'asset' => "somemovie.mov"
    ),
    array(
        'id' => 2,
        'name' => 'sally',
        'asset' => "anothersong.mp3"
    ),
    array(
        'id' => 2,
        'name' => 'sally',
        'asset' => "anothermovie.mov"
    )
);

$result = array();

$fields_map = array(
    '/\.mp3$/iS' => 'song',
    '/\.mov$/iS' => 'movie'
);

foreach($original_array as $item)
{
    $id = $item['id'];

    if (!isset($result[$id]))
    {
        // initial population
        $result[$id] = array(
            'id' => $id,
            'name' => $item['name']
        );
    }

    if (isset($item['asset']))
    {
        foreach($fields_map as $re => $field_name)
        {
            if (preg_match($re, $item['asset']))
            {
                $result[$id][$field_name] = $item['asset'];
                break;
            }
        }
    }
}

var_dump($result);

Note: I am using a regexp for the field_map instead of a simple hashmap on the file extensions because I assume you might have more extensions you need to support for the same fields (eg mp3, ogg, wav, flac all mapping to field 'song'). The regexp makes it is easy to add more fields.

Try this :

$array = array(
    array(
        'id' => 1,
        'name' => 'edwards',
        'asset' => "somesong.mp3"
    ),
    array(
        'id' => 1,
        'name' => 'edwards',
        'asset' => "somemovie.mov"
    ),
    array(
        'id' => 2,
        'name' => 'sally',
        'asset' => "anothersong.mp3"
    ),
    array(
        'id' => 2,
        'name' => 'sally',
        'asset' => "anothermovie.mov"
    )
);

$res   = array();

foreach($array as $val){
   $res[$val['id']]['id'] =  $val['id'];
   $res[$val['id']]['name'] =  $val['name'];
   if(preg_match('/mp3$/',$val['asset'])){
    $res[$val['id']]['song'] =  $val['asset'];
   }
   if(preg_match('/mov$/',$val['asset'])){
    $res[$val['id']]['movie'] =  $val['asset'];
   }
}
$res  = array_values($res);

echo "<pre>";
print_r($res);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM