Retrieve multiple array values with extract

12,489

Solution 1

$arr = array(
            array(
                'index1'=>'something',
                'index2'=>'something else',
                'index3'=>'something more',
            ),
            array(
                'index1'=>'something',
                'index2'=>'something else',
                'index3'=>'something more',
            ),
            array(
                'index1'=>'something',
                'index2'=>'something else',
                'index3'=>'something more',
            )
        );

$output = Set::classicExtract($arr, '{n}.{index[1-2]}');

print_r($output);

// output


Array
(
    [0] => Array
        (
            [index1] => something
            [index2] => something else
        )

    [1] => Array
        (
            [index1] => something
            [index2] => something else
        )

    [2] => Array
        (
            [index1] => something
            [index2] => something else
        )

)

Solution 2

One way (if you only want to keep a few results):

Hash::merge(
    Hash::extract($array, '{n}.index1'),
    Hash::extract($array, '{n}.index2')
);

Another way (if you only want to remove a few):

Hash::remove($array, '{n}.index3');

Solution 3

Set is AWESOME! You can't do this directly with Set::extract, but you CAN build an associative array of the the two array indexes using Set::combine:

Set::combine($myArray, '{n}.index1', '{n}.index2')

A working example looks like this:

$myArray = array(
    array('index1'=>'something 1', 'index2'=>'something else 1', 'index3'=>'something more 1'),
    array('index1'=>'something 2', 'index2'=>'something else 2', 'index3'=>'something more 2'),
    array('index1'=>'something 3', 'index2'=>'something else 3', 'index3'=>'something more 3'),
);

debug(Set::combine($myArray, '{n}.index1', '{n}.index2'));

This will take an array like you mentioned:

array(
[0]=>
    [index1]=>something 1
    [index2]=>something else 1
    [index3]=>something more 1
[1]=>
    [index1]=>something 2
    [index2]=>something else 2
    [index3]=>something more 2
[2]=>
    [index1]=>something 3
    [index2]=>something else 3
    [index3]=>something more 3

)

and turn it into this:

Array (
    [something1] => something else 1
    [something2] => something else 2
    [something3] => something else 3
)

Solution 4

Have you tried Set::extract($array, '{n}.{s}'); ?

EDIT: If your array dimension is exactly like the one in your answer, you could try array_keys(Set::extract($array, '{n}.{s}'));

Solution 5

I am not sure why you want to stick with the Set class ? If it doesn't suit your need, why would you absolutely use it and not create your own function ? You say in one of your comments that you want to avoid foreach loops. But the Set class methods are full of foreach loops themselve. I may miss the point...

Personnaly I would do it simply with a function like this one:

function filter_fields($array_to_filter, $fields_to_keep)
{
    foreach($array_to_filter as $i => $sub_array)
    {
        foreach($sub_array as $field => $value)
        {
            if(!in_array($field, $fields_to_keep))
            {
                unset($array_to_filter[$i][$field]);
            }
        }
    }

    return $array_to_filter;
}

Here is an example of what it would return:

print_r($array_to_filter);
/*
Array
(
    [0] => Array
        (
            [index1] => abc
            [index2] => def
            [index3] => ghi
        )

    [1] => Array
        (
            [index1] => jkl
            [index2] => mno
            [index3] => poq
        )
)
*/

$filtered_array = filter_fields($array_to_filter, array('index1', 'index3'));

print_r($filtered_array);
/*
Array
(
    [0] => Array
        (
            [index1] => abc
            [index3] => ghi
        )

    [1] => Array
        (
            [index1] => jkl
            [index3] => poq
        )
)
*/
Share:
12,489

Related videos on Youtube

Tim Joyce
Author by

Tim Joyce

I am a developer for php, html, css, javascript, jquery, and a few others. These are just the fun ones for me.

Updated on September 16, 2022

Comments

  • Tim Joyce
    Tim Joyce over 1 year
    array(
        [0]=>
            [index1]=>something
            [index2]=>something else
            [index3]=>something more
        [1]=>
            [index1]=>something
            [index2]=>something else
            [index3]=>something more
        [2]=>
            [index1]=>something
            [index2]=>something else
            [index3]=>something more
    )
    

    EDIT: So I would like to retrieve the following:

    array(
        [0]=>
            [index1]=>something
            [index2]=>something else
        [1]=>
            [index1]=>something
            [index2]=>something else
        [2]=>
            [index1]=>something
            [index2]=>something else
    )
    

    How do I get multiple indexes of the array using the Set::extract function in cakephp?

    This retrieves one value:

    Set::extract($array, '{n}.index1');
    

    but I would like to get multiple values ... say, index1 and index2.

    I tried statements like the following, to no avail.

    Set::extract($array, '[{n}.index1, {n}.index2']);
    

    EDIT

        $__pages = Hash::merge(
                        Hash::extract($pages, 'pages.{n}.id'),
                        Hash::extract($pages, 'pages.{n}.title')
                        );
        pr($__pages);
    

    Output:

    Array
    (
        [0] => 2
        [1] => 4
        [2] => 104
        [3] => Sample Page
        [4] => about us
        [5] => Services
    )
    

    That doesn't really help me since I still need the association like so:

    Array(
       [2] => Sample Page
       [4] => About us
       [104] => Services
    )
    

    I would even be happy with :

    Array(
       Array(id => 2, title => Sample Page)
       Array(id => 4, title => About Us)
       Array(id => 104, title => Services)
    )
    

    ANSWER thecodeparadox's answer works for the test code that I provided. Here is the real life code in case someone stumbles here. In the book it states, "any string literal enclosed in brackets besides {n} and {s}) is interpreted as a regular expression." This line seemed to be hidden and not very blatant. So knowing this, I simply used regex rules to retrieve the data I needed. I have an array that pulled wordpress posts from an api, I needed to narrow down the results to id, title.

    array(
       posts=>
          0=>
             id => 3
             slug => sample-page
             type => page
             title => Sample Page
             //...and so on 
    
          1=>
             id => 7
             slug => sample-page-2
             type => page
             title => Sample Page 2
             //...and so on 
    

    To retrieve just the id and title I added the following line.

    pr(Set::classicExtract($pages, 'pages.{n}.{(id|title)}'));
    

    this gave me:

    array(
       posts=>
          0=>
             id => 3
             title => Sample Page
    
          1=>
             id => 7
             title => Sample Page 2
    

    DOCUMENTATION: Book

  • Tim Joyce
    Tim Joyce over 11 years
    This will return all strings in the array.
  • Tim Joyce
    Tim Joyce over 11 years
    I see what you are saying. I should reword the question, I need the values to come along with the keys.
  • Marius
    Marius over 11 years
    I think I'm missing something here... Assuming you have this array: $array = array(array('index1'=>'something', 'index2'=>'something else', 'index3'=>'something more'), array('index1'=>'something', 'index2'=>'something else', 'index3'=>'something more')); then accesing the keys and values from the subarray is as easy as getting $array[index], no?
  • Tim Joyce
    Tim Joyce over 11 years
    I simplified the array. The array could have potentially hundreds of nested arrays with the same keys. Trying to avoid a foreach loop.
  • Marius
    Marius over 11 years
    I understand, but the question is: the keys from the second level array can repeat? like in my example above, where you have index1, index2 and index 3 in the second subarray, too? In this case what exactly do you want to get in the result? You should put an initial array with 2 or 3 subarrays and then an example array to specify the format of the array you want to get as a result
  • dogmatic69
    dogmatic69 over 11 years
    @TimJoyce you can not 'avoid a foreach', that is what Hash::* uses. Somewhere there will be a loop.
  • Tim Joyce
    Tim Joyce over 11 years
    I like your first approach here, and I think it's close. I updated my question to provide you with the output I got when doing that. The formatting is just a bit off because I still need the id and title to be an association. Thanks
  • Tim Joyce
    Tim Joyce over 11 years
    Thank you for your answer. When I said I wanted to avoid a foreach loop, it's because I already know how to do it that way. I was looking for a more "Cake" way of doing this. I feel the new cakephp documentation for 2.x is lacking in many ways and hoping someone has the answer. Since my migration to 2.x I have google searched most of my problems because of the lack of documentation. The api is great but the cookbook is not.
  • nIcO
    nIcO over 11 years
    I believe you that you know how to do it yourself :-) But if the Cake libraries can't, that is yet another reason to create your own function.
  • dogmatic69
    dogmatic69 over 11 years
    This can all be done in a single line, $filtered = Hash::remove($array, '{n}.index3');
  • nIcO
    nIcO over 11 years
    If we want to discard only one field, that's true. But with many more fields Hash::remove() would have to be called many times, which would be less performent.
  • thecodeparadox
    thecodeparadox over 11 years
    @Tim Joyce Please test my answer.. and I hope you'll get your desired answer. Thanks.
  • Tim Joyce
    Tim Joyce over 11 years
    Thanks for this. You answered my question and led me on the right path to research why this worked and I was able to adapt it to my real life code. I am updating my question with my findings.
  • mmv_sat
    mmv_sat about 8 years
    Looks like the set class is depreciated in favor of the Hash class