Ok, I am wanting to do something like this:
$which = !empty($param_id) ? "['groups'][$param_id]" : "['groups']";
And than I'd like it to be able to do something like so...
$all_groups . $which = array(
-1 => array(
'id' => '-1',
'name' => $txt['parent_guests_only'],
'checked' => in_array('-1', $checked) || in_array('-3', $checked),
'is_post_group' => false,
)
And I need it to build an array like so, if !empty($param_id)
$all_groups['groups'][$param_id] = array(the array info);
But if $param_id is empty it should do the this instead:
$all_groups['groups'] = array(the array info);
I don't think I can concatenate it or can I?
Can someone please help me here? This is happening many many times throughout a function, so I don't want to use if... else... statements every single time. Would be too many, thinking of a 1 fast approach for all of them.
Thanks :)
EDIT, here is the function in question:
function ListGroups($checked = array(), $unallowed = array(), $order = array(), $param_id = 0)
{
global $context, $smcFunc, $txt;
// We'll need this for loading up the names of each group.
if (!loadLanguage('ManageBoards'))
loadLanguage('ManageBoards');
if (empty($checked))
return array();
$all_groups['groups'][$param_id] = array();
if (!in_array('-1', $unallowed))
// Guests
$all_groups['groups'][$param_id] = array(
-1 => array(
'id' => '-1',
'name' => $txt['parent_guests_only'],
'checked' => in_array('-1', $checked) || in_array('-3', $checked),
'is_post_group' => false,
)
);
if (!in_array('0', $unallowed))
{
// Regular Members
if (!empty($all_groups['groups']))
$all_groups['groups'][$param_id] += array(
0 => array(
'id' => '0',
'name' => $txt['parent_members_only'],
'checked' => in_array('0', $checked) || in_array('-3', $checked),
'is_post_group' => false,
)
);
else
$all_groups['groups'][$param_id] = array(
0 => array(
'id' => '0',
'name' => $txt['parent_members_only'],
'checked' => in_array('0', $checked) || in_array('-3', $checked),
'is_post_group' => false,
)
);
}
// Load membergroups.
$request = $smcFunc['db_query']('', '
SELECT group_name, id_group, min_posts
FROM {db_prefix}membergroups
WHERE id_group > {int:is_zero}',
array(
'is_zero' => 0,
)
);
while ($row = $smcFunc['db_fetch_assoc']($request))
{
if (!in_array($row['id_group'], $unallowed))
{
$all_groups['groups'][(int) $param_id][(int) $row['id_group']] = array(
'id' => $row['id_group'],
'name' => trim($row['group_name']),
'checked' => in_array($row['id_group'], $checked) || in_array('-3', $checked),
'is_post_group' => $row['min_posts'] != -1,
);
}
}
$smcFunc['db_free_result']($request);
// Let's sort these arrays accordingly!
if (!empty($order))
{
$all_groups['groups'][$param_id] = sortGroups($all_groups['groups'][$param_id], $order);
$context['group_order' . $param_id] = implode(', ', $order);
}
else
{
$context['group_order' . $param_id] = '';
sort($all_groups['groups'][$param_id]);
$x = 0;
foreach ($all_groups['groups'][$param_id] as $key => $value)
{
$x++;
$context['group_order' . $param_id] .= $x < count($all_groups['groups'][$param_id]) ? $value['id'] . ', ' : $value['id'];
}
}
return $all_groups['groups'][$param_id];
}
I need to do a check for !empty($param_id), if so, it needs to build the $all_groups['groups'] array without the $param_id.
So will need to add in a check for if (!empty($params_id)) build the array like so: $all_groups['groups'][$params_id] else build it like this instead: $all_groups['groups']. I don't want a bunch of if... else... statements in here, just a 1 or 5 liner would be GREAT!
Thanks Guys :)
Don't overcomplicate it. :)
$array = array(
/* contents */
);
if (!empty($param_id)) {
$all_groups['groups'][$param_id] = $array;
} else {
$all_groups['groups'] = $array;
}
I don't know what $all_groups['groups'] looks like before this; if it was empty, I'd shorten this to:
$all_groups['groups'] = array(
/* contents */
);
if (!empty($param_id)) {
$all_groups['groups'] = array($param_id => $all_groups['groups']);
}
if (!empty($param_id)) {
$which = &$all_groups['groups'][$param_id]
} else {
$which = &$all_groups['groups'];
}
$which = array(
-1 => array(
'id' => '-1',
'name' => $txt['parent_guests_only'],
'checked' => in_array('-1', $checked) || in_array('-3', $checked),
'is_post_group' => false,
);
unset($which); // unset $which, if you want to use this variable
// in this scope once again
Generally speaking, references are the solution. See #zerkms' answer.
However, if at all possible, I would try to redesign your data structures such that you don't have to resort to this type of conditional behavior. For example, using default as the default missing key:
$which = !empty($param_id) ? $param_id : 'default';
$all_groups['groups'][$which] = array( ... );
I don't know if it's possible in your case, but this could be easier to manage.
Other potential solutions:
$tmp = array( ... );
if ($cond)
$foo = $tmp;
else
$bar = $tmp;
or:
function make_array( ... )
{
return array( ... );
}
if ($cond)
$foo = make_array( ... );
else
$bar = make_array( ... );
Related
I need elements of array 1 that are not present in array 2 based on the 'value' key only.
Array1
$array1 = array(
array('value' => 113214, 'revision_id' => 2047152),
array('value' => 236462, 'revision_id' => 2045678),
array('value' => 236541, 'revision_id' => 2047155)
);
Array2
$array2 = array(
array('value' => 113214, 'revision_id' => 2047152),
array('value' => 236461, 'revision_id' => 2047153),
array('value' => 236541, 'revision_id' => 2047155)
);
I need the output as below, the difference of arrays should be based on Value
$output = array(
array('value' => 236462, 'revision_id' => 2045678)
);
Just do a nested foreach loop and check the condition hope its helps you :
$arraycheck= array();
foreach($newData as $data1) {
$duplicatecheck = false;
foreach($oldData as $data2) {
if($data1['value'] === $data2['value'] && $data1['revision_id'] === $data2['revision_id']) $duplicatecheck = true;
}
if($duplicatecheck === false) $arraycheck[] = $data1;
}
First, use array_column to get the values of 'value' from array2 into a one-dimensional array:
$a2values = array_column($array2, 'value');
Then use those values to array_filter array1.
$result = array_filter($array1, function($item) use ($a2values) {
// only keep items with values not in array2
return !in_array($item['value'], $a2values);
});
You can use array_udiff which accepts last parameter as callback, and you can define your comparison there easily.
$array1 = [
['value' => '113214', 'revision_id' => '2047152'],
['value' => '236462', 'revision_id' => '2045678'],
['value' => '236541', 'revision_id' => '2047155'],
];
$array2 = [
['value' => '113214', 'revision_id' => '2047152'],
['value' => '236461', 'revision_id' => '2047153'],
['value' => '236541', 'revision_id' => '2047155'],
];
$result = array_udiff ($array1, $array2, function($x, $y) {
return $x['value'] - $y['value'];
});
print_r($result);
taken from: https://gist.github.com/wrey75/c631f6fe9c975354aec7
function my_array_diff($arr1, $arr2) {
$diff = array();
// Check the similarities
foreach( $arr1 as $k1=>$v1 ){
if( isset( $arr2[$k1]) ){
$v2 = $arr2[$k1];
if( is_array($v1) && is_array($v2) ){
// 2 arrays: just go further...
// .. and explain it's an update!
$changes = self::diff($v1, $v2);
if( count($changes) > 0 ){
// If we have no change, simply ignore
$diff[$k1] = array('upd' => $changes);
}
unset($arr2[$k1]); // don't forget
}
else if( $v2 === $v1 ){
// unset the value on the second array
// for the "surplus"
unset( $arr2[$k1] );
}
else {
// Don't mind if arrays or not.
$diff[$k1] = array( 'old' => $v1, 'new'=>$v2 );
unset( $arr2[$k1] );
}
}
else {
// remove information
$diff[$k1] = array( 'old' => $v1 );
}
}
// Now, check for new stuff in $arr2
foreach( $arr2 as $k=>$v ){
// OK, it is quite stupid my friend
$diff[$k] = array( 'new' => $v );
}
return $diff;
}
usage:
$diff = my_array_diff($arr1, $arr2);
var_dump($diff);
I searched in Google and consulted the PHP documentation, but couldn't figure out how the following code works:
$some='name=Licensing Module;nextduedate=2013-04-10;status=Active|name=Test Addon;nextduedate=2013-04-11;status=Active';
function getActiveAddons($somet) {
$addons = array( );
foreach ($somet as $addon) {
if ($addon['status'] == 'Active') {
$addons[] = $addon['name'];
continue;
}
}
return $addons;
}
echo (count( getActiveAddons( $some ) ) ? implode( '<br />', getActiveAddons( $some ) ) : 'None');
The code always echo's None.
Please help me in this.
I don't know where you got this code from but you've initialized $some the wrong way. It is expected as an array like this:
$some = array(
array(
'name' => 'Licensing Module',
'nextduedate' => '2013-04-10',
'status' => 'Active'
),
array(
'name' => 'Test Addon'
'nextduedate' => '2013-04-11',
'status' => 'Active'
)
);
I guess the article you've read is expecting you to parse the original string into this format.
You can achieve this like this:
$string = 'name=Licensing Module;nextduedate=2013-04-10;status=Active|name=Test Addon;nextduedate=2013-04-11;status=Active';
$result = array();
foreach(explode('|', $string) as $record) {
$item = array();
foreach(explode(';', $record) as $column) {
$keyval = explode('=', $column);
$item[$keyval[0]] = $keyval[1];
}
$result[]= $item;
}
// now call your function
getActiveAddons($result);
$some is not an array so foreach will not operate on it. You need to do something like
$some = array(
array(
'name' => 'Licensing Module',
'nextduedate' => '2013-04-10',
'status' => 'Active'
),
array(
'name' => 'Test Addon',
'nextduedate' => '2013-04-11',
'status'=> 'Active'
)
);
This will create a multidimensional array that you can loop through.
function getActiveAddons($somet) {
$addons = array( );
foreach ($somet as $addon) {
foreach($addon as $key => $value) {
if ($key == 'status' && $value == 'Active') {
$addons[] = $addon['name'];
continue;
}
}
}
return $addons;
}
First, your $some variable is just a string. You could parse the string into an array using explode(), but it's easier to just start as an array:
$some = array(
array(
"name" => "Licensing Module",
"nextduedate" => "2013-04-10",
"status" => "Active",
),
array(
"name" => "Test Addon",
"nextduedate" => "2013-04-11",
"status" => "Active",
)
);
Now, for your function, you are on the right track, but I'll just clean it up:
function getActiveAddons($somet) {
if (!is_array($somet)) {
return false;
}
$addons = array();
foreach ($somet as $addon) {
if ($addon['status'] == 'Active') {
$addons[] = $addon['name'];
}
}
if (count($addons) > 0) {
return $addons;
}
return false;
}
And finally your output (you were calling the function twice):
$result = getActiveAddons($some);
if ($result === false) {
echo "No active addons!";
}
else {
echo implode("<br />", $result);
}
$example =
array
'test' =>
array(
'something' => 'value'
),
'whatever' =>
array(
'something' => 'other'
),
'blah' =>
array(
'something' => 'other'
)
);
I want to count how many of $example's subarrays contain an element with the value other.
What's the easiest way to go about doing this?
array_filter() is what you need:
count(array_filter($example, function($element){
return $element['something'] == 'other';
}));
In case you want to be more flexible:
$key = 'something';
$value = 'other';
$c = count(array_filter($example, function($element) use($key, $value){
return $element[$key] == $value;
}));
You can try the following:
$count = 0;
foreach( $example as $value ) {
if( in_array("other", $value ) )
$count++;
}
This is sort of a general implementation question. If I have an arbitrarily deep array, and I do not know before hand what the keys will be, what is the best way to access the values at specific paths of the associative array? For example, given the array:
array(
'great-grandparent' = array(
'grandparent' = array(
'parent' = array(
'child' = 'value';
),
'parent2' = 'value';
),
'grandparent2' = 'value';
)
);
Whats the best way to access the value at $array['great-grandparent']['grandparent']['parent']['child'] keeping in mind that I don't know the keys beforehand. I have used eval to construct the above syntax as a string with variable names and then eval'd the string to get the data. But eval is slow and I was hoping for something faster. Something like $class->getConfigValue('great-grandparent/grandparent/'.$parent.'/child'); that would return 'value'
Example of Eval Code
public function getValue($path, $withAttributes=false) {
$path = explode('/', $path);
$rs = '$r = $this->_data[\'config\']';
foreach ($path as $attr) {
$rs .= '[\'' . $attr . '\']';
}
$rs .= ';';
$r = null;
#eval($rs);
if($withAttributes === false) {
$r = $this->_removeAttributes($r);
}
return $r;
}
I don't know about the potential speed but you don't need to use eval to do a search like that :
$conf = array(
'great-grandparent' => array(
'grandparent' => array(
'parent' => array(
'child' => 'value searched'
),
'parent2' => 'value'
),
'grandparent2' => 'value'
)
);
$path = 'great-grandparent/grandparent/parent/child';
$path = explode('/', $path);
$result = $conf;
while(count($path) > 0) {
$part = array_shift($path);
if (is_array($result) && array_key_exists($part, $result)) {
$result = $result[$part];
} else {
$result = null;
break;
}
}
echo $result;
Here we go, my solution:
$tree = array(
'great-grandparent' => array(
'grandparent' => array(
'parent' => array(
'child' => 'value1'
),
'parent2' => 'value2'
),
'grandparent2' => 'value3'
)
);
$pathParts = explode('/','great-grandparent/grandparent/parent/child');
$pathParts = array_reverse($pathParts);
echo retrieveValueForPath($tree, $pathParts);
function retrieveValueForPath($node, $pathParts) {
foreach($node as $key => $value) {
if(($key == $pathParts[count($pathParts)-1]) && (count($pathParts)==1)) {
return $value;
}
if($key == $pathParts[count($pathParts)-1]) {
array_pop($pathParts);
}
if(is_array($value)) {
$result = retrieveValueForPath($value, $pathParts);
}
}
return $result;
}
I have a deep and long array (matrix). I only know the product ID.
How found way to product?
Sample an array of (but as I said, it can be very long and deep):
Array(
[apple] => Array(
[new] => Array(
[0] => Array([id] => 1)
[1] => Array([id] => 2))
[old] => Array(
[0] => Array([id] => 3)
[1] => Array([id] => 4))
)
)
I have id: 3, and i wish get this:
apple, old, 0
Thanks
You can use this baby:
function getById($id,$array,&$keys){
foreach($array as $key => $value){
if(is_array( $value )){
$result = getById($id,$value,$keys);
if($result == true){
$keys[] = $key;
return true;
}
}
else if($key == 'id' && $value == $id){
$keys[] = $key; // Optional, adds id to the result array
return true;
}
}
return false;
}
// USAGE:
$result_array = array();
getById( 3, $products, $result_array);
// RESULT (= $result_array)
Array
(
[0] => id
[1] => 0
[2] => old
[3] => apple
)
The function itself will return true on success and false on error, the data you want to have will be stored in the 3rd parameter.
You can use array_reverse(), link, to reverse the order and array_pop(), link, to remove the last item ('id')
Recursion is the answer for this type of problem. Though, if we can make certain assumptions about the structure of the array (i.e., 'id' always be a leaf node with no children) there's further optimizations possible:
<?php
$a = array(
'apple'=> array(
'new'=> array(array('id' => 1), array('id' => 2), array('id' => 5)),
'old'=> array(array('id' => 3), array('id' => 4, 'keyname' => 'keyvalue'))
),
);
// When true the complete path has been found.
$complete = false;
function get_path($a, $key, $value, &$path = null) {
global $complete;
// Initialize path array for first call
if (is_null($path)) $path = array();
foreach ($a as $k => $v) {
// Build current path being tested
array_push($path, $k);
// Check for key / value match
if ($k == $key && $v == $value) {
// Complete path found!
$complete= true;
// Remove last path
array_pop($path);
break;
} else if (is_array($v)) {
// **RECURSION** Step down into the next array
get_path($v, $key, $value, $path);
}
// When the complete path is found no need to continue loop iteration
if ($complete) break;
// Teardown current test path
array_pop($path);
}
return $path;
}
var_dump( get_path($a, 'id', 3) );
$complete = false;
var_dump( get_path($a, 'id', 2) );
$complete = false;
var_dump( get_path($a, 'id', 5) );
$complete = false;
var_dump( get_path($a, 'keyname', 'keyvalue') );
I tried this for my programming exercise.
<?php
$data = array(
'apple'=> array(
'new'=> array(array('id' => 1), array('id' => 2), array('id' => 5)),
'old'=> array(array('id' => 3), array('id' => 4))
),
);
####print_r($data);
function deepfind($data,$findfor,$depth = array() ){
foreach( $data as $key => $moredata ){
if( is_scalar($moredata) && $moredata == $findfor ){
return $depth;
} elseif( is_array($moredata) ){
$moredepth = $depth;
$moredepth[] = $key;
$isok = deepfind( $moredata, $findfor, $moredepth );
if( $isok !== false ){
return $isok;
}
}
}
return false;
}
$aaa = deepfind($data,3);
print_r($aaa);
If you create the array once and use it multiple times i would do it another way...
When building the initial array create another one
$id_to_info=array();
$id_to_info[1]=&array['apple']['new'][0];
$id_to_info[2]=&array['apple']['new'][2];