PHP: not looping inside a foreach - php

I have this array:
$flavours = array (
0 => array(799390 => 'Banana',),
1 => array(799391 => 'Chocolate',)
);
And now I inside a foreach looping a set from my database. I get 'Banana' from the database and I need the array to give me 799390.
I have tried:
‌‌array_search('Banana', $flavours);
but it does not work unless I add:
‌‌array_search('Banana', $flavours[0]);
But I cannot add [0] as I won't be able to tell in which position 'Banana' flavour is in the array.
Any solution apart from looping again inside a foreach??
Thanks a ton

First, we can use array_walk_recursive() to flatten your array, which just gets rid of your nested arrays.
Next, we use array_flip() to swap the keys/values in the flattened array. This makes it easier to grab the ID for a specific term.
<?php
$flavours = [
[799390 => 'Banana'],
[799391 => 'Chocolate']
];
//flatten array
//Produces: Array ( [799390] => Banana [799391] => Chocolate )
array_walk_recursive($flavours,
function($v, $k) use (&$temp) {
$temp[$k] = $v;
}
);
//flip array. Swaps keys with values.
//Produces: Array ( [Banana] => 799390 [Chocolate] => 799391 )
$flavours = array_flip($temp);
Now you can get the ID pretty easily, such as $flavours['Banana'].
If you have a very very large array, this method may become slow. However, I tested this with 100,000 values on my cheap webhost, and ran this method a few times (20-25 times). It is finishing consistently at around (usually under) 0.1 milliseconds, which is about 0.0014 seconds.

You can insert an if statement to set a condition for your loop as
foreach ($flavours as $key => $value) {
if($key = array_search('Banana', $value)){
echo $key;
}
}
Output
799390

If the word being searched for is a different case many of the usual array methods will not work when trying to find the match, using preg_grep however will allow matches to be found in a case-insensitive manner.
function findflavour( $search, $haystack ){
foreach( $haystack as $index => $arr ){
$res=preg_grep( sprintf( '#%s#i', $search ), $arr );
if( !empty( $res ) ) return array_search( array_values( $res )[0], $arr );
}
return false;
}
$search='BaNanA';
$flavours=array(
array( 799390 => 'Banana' ),
array( 799391 => 'Chocolate' ),
array( 729361 => 'Chilli' ),
array( 879695 => 'Apple' ),
array( 995323 => 'Avacado' ),
array( 528362 => 'Orange' ),
array( 723371 => 'Cherry' ),
);
printf( 'Key:%s', findflavour( $search, $flavours ) );
If there might be multiple elements in the source array with the same value but different IDs a slightly different version of the findflavour function
function findflavour( $search, $haystack, $multiple=false ){
$keys=[];
foreach( $haystack as $index => $arr ){
$res=preg_grep( sprintf( '#%s#i', $search ), $arr );
if( !empty( $res ) ) {
$key=array_search( array_values( $res )[0], $arr );
if( $multiple )$keys[]=$key;
else return $key;
}
}
return $multiple ? $keys : false;
}
$multiple=true;
$search='AVacAdo';
$flavours=array(
array( 799390 => 'Banana' ),
array( 799391 => 'Chocolate' ),
array( 291333 => 'Avacado' ),
array( 729361 => 'Chilli' ),
array( 879695 => 'Apple' ),
array( 995323 => 'Avacado' ),
array( 528362 => 'Orange' ),
array( 723371 => 'Cherry' ),
);
printf( 'Key(s): %s', print_r( findflavour( $search, $flavours, $multiple ), true ) );

Related

PHP - Convert information supplied in a string format to an array format

$attribute_options_string = "Spice (Very Hot/3, Hot/2, Medium/1) | Size(Small,Medium,Large)";
$attribute_options_array = array(
'spice' => array(
'very hot' =>3,
'hot' => 2,
'medium' => 1
),
'size' => array(
'small',
'medium',
'large'
)
);
I am trying to write a function that converts the string format to the array format.
As was succinctly described by #tim in the comments, you just need to:
explode on pipe, loop, explode on comma, loop, explode on slash if needed
It's not quite that simple as you need to extract the option name, and since you seem to have variable spacing in your strings it's safer to use preg_split rather than explode. Based on your sample data, this will work:
$attribute_options_string = "Spice (Very Hot/3, Hot/2, Medium/1) | Size(Small,Medium,Large)";
$attribute_options_array = array();
$attributes = preg_split('/\s*\|\s*/', $attribute_options_string);
foreach ($attributes as $attribute) {
preg_match('/\s*(\w+)\s*\(([^)]+)/', $attribute, $matches);
$attribute_name = strtolower($matches[1]);
$options = preg_split('/\s*,\s*/', $matches[2]);
foreach ($options as $option) {
if (strpos($option, '/') !== false) {
list($option_name, $option_value) = preg_split('#\s*/\s*#', $option);
$attribute_options_array[$attribute_name][strtolower($option_name)] = $option_value;
}
else {
$attribute_options_array[$attribute_name][] = strtolower($option);
}
}
}
var_export($attribute_options_array);
Output:
array (
'spice' => array (
'very hot' => '3',
'hot' => '2',
'medium' => '1',
),
'size' => array (
0 => 'small',
1 => 'medium',
2 => 'large',
),
)
Demo on 3v4l.org

remove certain keys from an assoc. array

I have two arrays:
$pool = array(
'foo' => array('foobar1'),
'bar' => array('foobar2'),
'lou' => array('foobar3'),
'zuu' => array('foobar4')
);
$remove = array('lou', 'zuu');
How do I get this array:
$result = array(
'foo' => array('foobar1'),
'bar' => array('foobar2')
);
I can do a foreach loop but I like a more elegant solution like
$result = array_intersect_key( $pool, array_flip($remove) );
which gives me the other way:
array(
'lou' => array('foobar3'),
'zuu' => array('foobar4')
);
EDIT: my one line solution is:
array_intersect_key( $pool, array_flip( array_keys( array_diff_key( $pool, array_flip( $remove ) ) ) ) )
try this then
$pool = array(
'foo' => array('foobar1'),
'bar' => array('foobar2'),
'lou' => array('foobar3'),
'zuu' => array('foobar4')
);
$remove = array('lou', 'zuu');
$compare=array_diff_key($pool, array_flip($remove));
var_dump(array_intersect_key($pool,$compare));
Use unset function
unset($pool['lou']);

Retrieve all parent keys of a given child key in Array

I've been breaking my head over this one but can't seem to find a solution. I need a function that retrieves all parent keys of a given child key. So for example if I have an array like this:
array(
'apples' => array(
'bananas' => array(
'strawberries' => array(
'fruit' => array()
)
)
)
)
I would call the function like 'key_get_parents($key, $array)', and it would return an array with all the parent keys. In this example that would be array('apples', 'bananas', 'strawberries').
$array = array(
'apples' => array(
'bananas' => array(
'strawberries' => array(
'fruit' => array()
)
)
)
);
function key_get_parents($subject, $array)
{
foreach ($array as $key => $value)
{
if (is_array($value))
{
if (in_array($subject, array_keys($value)))
return array($key);
else
{
$chain = key_get_parents($subject, $value);
if (!is_null($chain))
return array_merge(array($key), $chain);
}
}
}
return null;
}
// Prints "Array ( [0] => apples [1] => bananas )"
print_r(key_get_parents('strawberries', $array));

PHP: how to create associative array by key?

I have simple array
array(
array( 'id'=>5, 'something' => 2, 'dsadsa' => 'fsfsd )
array( 'id'=>20, 'something' => 2, 'dsadsa' => 'fsfsd )
array( 'id'=>30, 'something' => 2, 'dsadsa' => 'fsfsd )
)
How to create associative array by id field (or something else) from it in the right way?
array(
'5' => array( 'something' => 2, 'dsadsa' => 'fsfsd )
'20' => array( 'something' => 2, 'dsadsa' => 'fsfsd )
'30' => array( 'something' => 2, 'dsadsa' => 'fsfsd )
)
Something along these lines.
$new_array = array();
foreach ($original_array as &$slice)
{
$id = (string) $slice['id'];
unset($slice['id']);
$new_array[$id] = $slice;
}
#NikitaKuhta, nope. There is no slice function which returns a column of values in a 2D keyed table associated with a given key or column heading. You can use some of the callback array_... functions, but you will still need to execute a custom function per element so its just not worth it. I don't like Core Xii's solution as this corrupts the original array as a side effect. I suggest that you don't use references here:
$new_array = array();
foreach ($original_array as $slice) {
$id = (string) $slice['id'];
unset($slice['id']);
$new_array[$id] = $slice;
}
# And now you don't need the missing unset( $slice)

How do I transform this array into a multi-dimensional array via recursion?

So my example inputs are
$example_1 = Array (
0 => Array (
'category' => 'body',
'sub-category' => 'intro',
'id' => 'header',
'copy' => 'Hello',
),
1 => Array (
'category' => 'body',
'sub-category' => 'intro',
'id' => 'footer',
'copy' => 'Bye',
),
);
$example_2 = Array (
0 => Array (
'category' => 'body',
'sub-category' => 'intro',
'sub-sub-category' => 'header',
'sub-sub-child-category' => 'left',
'id' => 'title',
'copy' => 'Hello',
),
1 => Array (
'category' => 'body',
'sub-category' => 'intro',
'sub-sub-category' => 'footer',
'sub-sub-child-category' => 'right',
'id' => 'title',
'copy' => 'Bye',
),
);
I want to transform it into
$example_output_1 = Array (
'body' => Array (
'intro' => Array (
'header' => Array (
'title' => 'Hello',
),
'footer' => Array (
'title' => 'Bye',
),
),
),
);
$example_output_2 = Array (
'body' => Array (
'intro' => Array (
'header' => Array (
'left' => Array (
'title' => 'Hello',
),
),
'footer' => Array (
'right' => Array (
'title' => 'Bye',
)
),
),
),
);
Note the depth of the array is dynamic (it is not set - only by the time it hits 'copy' does it indicate the depth of the array).
I am having problems trying to get the recursion correctly. The basic but very rough algorithm I had was to
- Loop through the Row
- Loop through the contents of the Row
- When the index is "copy" then the final value is current value.
- Then build the array
I managed to get it to process for ONLY one row of the array but it was very messy and kinda patchy, so I got a feeling I really need to start from scratch.
Updated: Attached embarrassing Code as requested (don't scream! ;p)
function buildArray($row, $start = true) {
if ($start) {
$result = array();
}
if ( ! is_array($row) ) {
return $row;
}
// Get the first element of the array include its index
$cellValue = null;
$colId = null;
foreach($row AS $index => $value) {
$cellValue = $value;
$colId = $index;
break;
}
// Reduce the array by one
$tempRow = $row;
$temp = array_shift($tempRow);
if ($colId == 'copy') {
$result[$cell] = buildArray($cellValue, $locale, false);
} else {
$result[$cell] = buildArray($tempRow, $locale, false);
}
return $result;
}
Any help will be greatly appreciated.
Should be pretty straightforward:
$originalArray = array(); // <-- should contain your values
$newArray = array();
foreach( $originalArray as $item )
{
$category = $item['category'];
$subcategory = $item['sub-category'];
if ( empty( $newArray[$category] ) )
{
$newArray[$category] = array();
}
if ( empty( $newArray[$category][$subcategory] ) )
{
$newArray[$category][$subcategory] = array();
}
$newArray[$category][$subcategory][$item['id']] = $item['copy'];
}
See it here in action: http://codepad.viper-7.com/9bDiLP
Update: Now that you've specified that you need unlimited recursion, here's a shot at that:
$originalArray = array(); // <-- Your values go here
$newArray = array();
foreach ( $originalArray as $item )
{
$inception = &$newArray; // http://www.imdb.com/title/tt1375666/
foreach ( $item as $key => $val )
{
if ( $key != 'id' )
{
if ( empty($inception[$val]) )
{
$inception[$val] = array();
}
$inception = &$inception[$val];
}
else
{
$inception[ $val ] = $item['copy'];
break;
}
}
}
...and here's the demo: http://codepad.viper-7.com/F9hY7h
This can be solved iteratively, because the recursion would only happen at the tail end of your function. The following code is the simplification. It builds a new layered array while it iterates over the old.
After transforming each each entry it gets merged using array_merge_recursive.
function transform($a)
{
// create new array and keep a reference to it
$b = array(); $cur = &$b;
foreach ($a as $key => $value) {
if ('id' === $key) {
// we're done, add value to the array built so far using id and copy
$cur[$value] = $a['copy'];
break;
} else {
// create one more level
$cur[$value] = array();
// and update the reference
$cur = &$cur[$value];
}
}
// all done
return $b;
}
// $example_2 is your multi-dimensional array
$merged = call_user_func_array('array_merge_recursive',
array_map('transform', $example_2)
);

Categories