8

This is a typical array structure:

$s = array ('etc'=>'etc', 'fields' => 
  array (
   0 => array (
     'name'=>'year', 'description'=>'Year of ...', 'type'=>'integer',
   ),
   1 =>  array (
     'name'=>'label', 'description'=>'Offical short name', type'=>'string',
   ),
   2 => array (
     'name' => 'xx', 'description' => 'Xx ...', 'type' => 'string',
   )
 ));

Here is a non-elegant way (or "not so elegant way") to reduce the big array to a simple array containing just one column:

 $fields = array();
 foreach ($strut['resources'][0]['schema']['fields'] as $r)
    $fields[] = $r['name'];

This works, but is it possible to do the same with only one instruction? Perhaps using like array_reduce(), but I not see how.


Here are other typical "elegance PHP problem":

 $fieldsByName = array();
 foreach ($strut['resources'][0]['schema']['fields'] as $r)
    $fields[$r['name']] = array(
        'description' =>$r['description'],
        'type' =>$r['type']
    );

Is there a PHP alternative? The idea here is to use the keyword (name in the example) as an array key, and the other elements as usual fields, so, the generic non-elegant algorithm is

 $fieldsByName = array();
 foreach ($strut['resources'][0]['schema']['fields'] as $r){
    $key = $r['name'];
    unset($r['name']);
    $fields[$key] = $r;
 }
Peter Krauss
  • 13,174
  • 24
  • 167
  • 304

3 Answers3

5

You can use array_column to extract all values with key name into another array

$names = array_column($strut['resources'][0]['schema']['fields'], 'name');
FuzzyTree
  • 32,014
  • 3
  • 54
  • 85
  • I agree with you ,, we should simplify the problem like we need all the sub array inside main array which has 'name' as a key – Mohammad Alabed Mar 22 '15 at 22:13
  • thanks, you was fast and precise (!)... Some good clue to the second problem? – Peter Krauss Mar 22 '15 at 22:58
  • @PeterKrauss Second problem will require more function calls… there's nothing builtin just for that. But a nice one-liner would be `$fields = array_combine(array_column($your_array, 'name'), array_map(function($array) { return array_diff_key($array, ["name" => 1]); }, $your_array));`. — And yes… you need to iterate somehow over that array… via foreach or array_map… doesn't matter. There's nothing built-in to get an array without a certain key (like array_column, just that it doesn't return all of that index, but all without that index). For that case you're really better off with the foreach… – bwoebi Mar 23 '15 at 00:28
  • @bwoebi, thanks (!), perhaps Python have something more elegant than PHP :-) Yes, some `foreach` can be elegant when comparing with "array_combine of array_column of array_map of array_diff_key"... It is PHP... Your solution without the `unset($r['name'])` was good (!), perhaps is util for other reader: `$x0 = array_combine( array_column($strut['x'][0],'name'), array_diff_key($strut['x'][0],['name'=>1])` – Peter Krauss Mar 23 '15 at 00:44
2

you could put your array thru this function:

function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}

it will result in just a literal sequence of just values of your multidimensional array, like so.

Array
(
    [0] => etc
    [1] => year
    [2] => Year of ...
    [3] => integer
    [4] => day
    [5] => Day of the ...
    [6] => string
    [7] => xx
    [8] => Xx ...
    [9] => string
)

then, as you know original structure - you can parse this how needed. 4ex: every third value could be new assoc array's key value that holds an array with arrays of first two values.., or as you wish

array_column is first logical announcement, no surprises there.

animaacija
  • 170
  • 9
  • 25
2

Depending on how normalized your data is and how often this issues comes up, you could implement a class around your data. You can use the ArrayAccess, Iterator and Countable to make the change completely transparent, and you would be able to implement helper methods to hide the complexity of fetching data.

Here is an example, just using ArrayAccess:

class Strut implements ArrayAccess {

    private $data;
    private $fieldsByName = null;

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

    public function fieldsByName() {
        //If the result has not already been computed
        if($this->fieldsByName === null) {
            $this->fieldsByName = array();
            foreach($this->data['resources'][0]['schema']['fields'] as $r) {
                $this->fieldsByName[ $r['name'] ] = array(
                    'description' =>$r['description'],
                    'type' =>$r['type']
                );
            }
        }

        return $this->fieldsByName;
    }

    /**
     * ArrayAccess Methods
     */
    public function offsetSet($offset, $value) {
        $this->data[$offset] = $value;
    }

    public function offsetExists($offset) {
        return isset( $this->data[$offset] );
    }

    public function offsetUnset($offset) {
        unset( $this->data[$offset] );
    }

    public function offsetGet($offset) {
        return isset( $this->data[$offset] ) ? $this->data[$offset] : null;
    }

}

Using the above code you should be able to access your data just has you have been, but you also have the option of defining additional accessors in a nice container. Note that you also have to implement the Iterator interface to be able to foreach over your data.

This doesn't address the "elegance" issue of the underlying implementation (the other solutions do a nice job of that), but this way hides the complexity completely.

Mathew Tinsley
  • 6,805
  • 2
  • 27
  • 37
  • Yes, "hide the complexity" in a library or a framework is also a good idea, but my first interest was in the PHP build-in solutions (see `array_column()`!)... So, if PHP have no solution (do you have some to the second problem?), them we must appeal to the library, expressed in an elegant class as you suggested. – Peter Krauss Mar 22 '15 at 23:03