I have two associative arrays
$reference = array(
'type_drink' => 'value',
'type_plate' => 'value',
'type_fork' => 'value',
'non_type' => 'value'
);
$target = array(
'type_plate' => 'value other',
'type_drink' => 'value other'
);
What's a nice way to re-order target to match $reference order of keys and ignoring keys that are not present in $target so that the final
$target = array(
'type_drink' => 'value other',
'type_plate' => 'value other'
);
Not sure if this is what you need, but here's what I interpret what you're asking for.
foreach($reference as $key => $val)
{
if(isset($target[$key]))
$tmp[$key] = $target[$key];
}
$target = $tmp;
http://php.net/manual/en/function.array-intersect-key.php and http://php.net/manual/en/function.ksort.php
ksort(array_intersect_key($target, $reference));
Related
I'm looking for a function to search for a matching keyword in a multi dimensional array and return the corresponding name and path values.
$search_array = array(
array(
'keywords' => array('apple', 'orange'),
'name' => 'Url One',
'path' => 'http://www.urlone.com'
),
array(
'keywords' => array('bananna'),
'name' => 'Url Two',
'path' => 'http://www.urltwo.com'
)
)
If there's a better way to structure this array to make it simpler the that would also be great, thanks
This can be accomplished using array filter:
$matches = array_filter($search_array, function($array){
return in_array('bananna', $array['keywords']);
});
Or using a foreach loop:
$matches = [];
foreach ($search_array as $key => $array) {
if (in_array('apple', $array['keywords'])) {
$matches[$key] = $search_array[$key];
}
}
Let's say I have an array formatted like so:
$data = array(
'variables' => array(
'823h9fhs9df38h4f8h' => array(
'name' => 'Foo',
'value' => 'green'
),
'sdfj93248fhfhf88rh' => array(
'name' => 'Bar',
'value' => 'red'
)
)
);
Say I wanted to access the name & values of each array in the variables array. Surely you can access it just looping over the main variables array and not looping over each individual item array? Something like so?
foreach ($data as $k => $v) {
$name = $data['variables'][0]['name'];
}
I'm sure I'm missing something simple...
You can do
foreach ($data['variables'] as $k => $v) {
$name = $v['name'];
}
You can also try this
create a new array containing just the names..
$new_arr = array_column($data['variables'],'name' );
echo $new_arr[0].'<br/>';
echo $new_arr[1].'<br/>';
What I'd like to do is have a function that accepts two arguments, both arrays, the first being a one-dimensional array of varying lengths and the second is a multi-dimensional array of varying depths and lengths. The first array is never associative, the second is always a fully associative array.
This function would return the requested value from the multi-dimensional array as indicated by the first array.
Assume that the first array will always be hand-written and passed to this function. Meaning the developer always knows there is a value to be returned from the multi-dimensional array and would never pass a request to the function where a value did not exist.
I think the code below is the best example at what I'm trying to achieve.
//Example multi-dimensional array
$multi = array(
'fruit' => array(
'red' => array(
'strawberries' => '$2.99/lb',
'apples' => '$1.99/lb'
),
'green' => array(
'honeydew' => '$3.39/lb',
'limes' => '$0.75/lb'
)
),
'vegetables' => array(
'yellow' => array(
'squash' => '$1.29/lb',
'bellpepper' => '$0.99/lb'
),
'purple' => array(
'eggplant' => '$2.39/lb'
)
),
'weeklypromo' => '15% off',
'subscribers' => array(
'user1#email.com' => 'User 1',
'user2#email.com' => 'User 2',
'user3#email.com' => 'User 3',
'user4#email.com' => 'User 4'
)
);
//Example one-dimensional array
$single = array('fruit', 'red', 'apples');
function magicfunc($single, $multi) {
//some magic here that looks something like below
$magic_value = $multi[$single[0]][$single[1]][$single[2]];
return $magic_value;
}
//Examples:
print magicfunc(array('fruit', 'red', 'apples'), $multi);
Output:
$1.99/lb
print magicfunc(array('subscribers', 'user3#email.com'), $multi);
Output:
User 3
print magicfunc(array('weeklypromo'), $multi);
Output:
15% off
This returns the values as requested:
function magicfunc($single, $multi) {
while (true) {
if (!$single) {
break;
}
$searchIndex = array_shift($single);
foreach ($multi as $k => $val) {
if ($k == $searchIndex) {
$multi = $val;
continue 2;
}
}
}
return $multi;
}
I'm checking to make sure an array of arrays does not contain certain strings before adding any new child arrays to the parent array
I want to make sure that if an array with the same website and condition exists a new child array will not be added to the parent array.
e.g. in this example the $newArr must not be inserted in to the array $arr because their already exists an array with the same website and condition.
$arr = array(
array(
'website' => 'amazon',
'price' => 20,
'location' => 'uk',
'link' => '...',
'condition' => 'new'
),
array(
'website' => 'abe',
'price' => 20,
'location' => 'uk',
'link' => '...',
'condition' => 'new'
)
);
$newArr = array(
'website' => 'amazon',
'price' => 60,
'location' => 'uk',
'link' => '...',
'condition' => 'new'
)
I'm looking for an easy solution as using the function in_array on the parent array is not enough.
code so far
$arr = array();
foreach($table->find('tr.result') as $row){
if(($website = $row->find('a img',0))
&& ($price = $row->find('span.results-price a',0))
&& ($location = $row->find('.results-explanatory-text-Logo'))
&& ($link = $row->find('a',0))){
$website = str_replace( array('.gif','.jpg','.png'), '', basename($website->src));
$price = floatval(trim(str_replace(',', '', $price->innertext), "£"));
$location = "uk";
$link = $link->href;
$arr[] = array(
'website' => $website,
'price' => $price,
'location' => $location,
'link' => $link,
'condition' => 'new'
);
}
}
You loop over $arr each time to look for $website and $condition (always 'new'?) or you can keep a secondary array of the found keys. If you're starting with an empty $arr each time, the second approach will work and be faster.
$arr = array();
$keys = array();
foreach($table->find('tr.result') as $row){
if(...){
...
$condition = 'new'; // set as needed
// track seen keys
$key = $website . '|' . $condition; // assumes neither field contains '|'
if (!isset($keys[$key])) {
$keys[$key] = true;
$arr[] = array(...);
}
}
}
I hope the comments in the below code speak for themselves... I'm not a PHP pro, and this is probably not the most elegant way, but I believe the logic makes sense. Obviously the $new_array object has some variables that aren't declared but it's for example only.
I hope that helps and that no one down votes me :)
<?php
// Original array
$arr = array();
foreach($result as $row) {
// Get the new array as an object first so we can check whether to add to the loop
$new_array = array(
'website' => $website,
'price' => $price,
'location' => $location,
'link' => $link,
'condition' => 'new'
);
// If the original array is empty there's no point in looping through it
if(!empty($arr)) {
foreach($arr as $child) {
// Check through each item of the original array
foreach($new_array as $compare) {
// Compare each item in the new array against the original array
if(in_array($compare, $child)) {
// if there's a match, the new array will not get added
continue;
}
}
}
}
// If there's no match, the new array gets added
$arr[] = $new_array;
}
?>
I have
$map = array('id' => 'clmId', 'name' => 'clmName' => 'value' => 'clmValue',);
$value = array('id' => 1, 'name' => 'Foo', 'value' => 'Bar',);
and I want to get
$expected = array('clmId' => 1, 'clmName' => 'Foo', 'clmValue' => 'Bar');
of course I did $expected = array_combine($map, $value) and it works most of the time, but fails (to my surprise) for following
$map = array('id' => 'clmId', 'name' => 'clmName' => 'value' => 'clmValue',);
$value = array('name' => 'Foo', 'id' => 1, 'value' => 'Bar',);
$expected = array_combine($map, $value);
//you get
//$expected = array('clmId' => Foo, 'clmName' => 1, 'clmValue' => 'Bar');
clearly, array_combine is not meant for combining associative arrays. What can be done to achieve this ?
I am doing a primitive foreach($map as $key => $mapValue) { ... but I am guessing a smarter map/reduce or some cool array function should do it for me.
Return array()/FALSE in case $value has no corresponding key from $map
function combine_if_same_keys( $array_one, $array_two ) {
$expected = false;
ksort($array_one);
ksort($array_two);
$diff = array_diff_key($array_one, $array_two);
if( empty($diff) && count($array_one) == count($array_two) ) {
$expected = array_combine( $array_one, $array_two );
}
return $expected;
}
Returns false if the keys don't match and an array if they did match.
$map = array('id' => 'clmId', 'name' => 'clmName', 'value' => 'clmValue');
$value = array('id' => 1, 'name' => 'Foo', 'value' => 'Bar');
$value2 = array('ids' => 1, 'name' => 'Foo', 'value' => 'Bar');
var_dump( combine_if_same_keys( $map, $value ) );
var_dump( combine_if_same_keys( $map, $value2 ) );
Outputs:
array(3) { ["clmId"]=> int(1) ["clmName"]=> string(3) "Foo" ["clmValue"]=> string(3) "Bar" }
bool(false)
Edit: Benchmarking
Just read some comments on another answer which suggested that ksort() will cause a performance hit, so I did a bit of benchmarking Ran ksort() on 2 arrays with (albeit numeric keyed arrays) 10,000,000 keys each which only took 0.010757923126221 seconds on
Intel Q8200 # 2.33ghz (4CPUs), 3072MB RAM, Windows 7 x64 .
Edit (by OP): Number of keys should match as well
array_diff_key($a1, $a2) returns empty array even if count($a2) > count($a1), the array_combine returns FALSE while generating a warning.
One can suppress it by #array_combine, but I would rather put the count condition (along with the appropriate empty() test on the array_key_diff return) and then combine the array.
I think there is no builtin way
function combine_assoc($map, $values) {
$output = array();
foreach($map as $key => $values) {
if(!array_key_exists($key, $value)) return FALSE;
$output[$value] = $values[$key];
}
return $output;
}
Of course, you could simply sort your arrays by key first, but this does not take care of missing key/value pairs and has a somewhat decreased performance:
ksort($map);
ksort($value);
$output = array_combine($map, $value);
Version without foreach loop, which does check for matching keys, but I do not recommend it, since it will not perform well …
function combine_assoc_slow($map, $value) {
ksort($map);
ksort($value);
if(array_keys($map) != array_keys($value)) return FALSE;
return array_combine($map, $value);
}
So array_combine doesn't work if the order is different? Well, easiest solution for you: sorting both arrays by key!
$map = array('id' => 'clmId', 'name' => 'clmName' => 'value' => 'clmValue');
$value = array('name' => 'Foo', 'id' => 1, 'value' => 'Bar');
ksort($map);
ksort($value);
// keys are "aligned", ready to combine
$expected = array_combine($map, $value);