I have an array with 3 sub arrays like:
$array = array(
width => array(
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5
),
height => array(
0 => 1,
1 => 2,
2 => 7,
3 => 8
),
color => array(
0 => 2,
1 => 7,
2 => 8
)
);
The count is in this case 3 as I have 3 arrays. This can be sometimes more or less, that's why I have a count.
Now I want to find out which number is in all 3 arrays and only use those. in above example the only returned number should be 2 as it's present in all 3 sub arrays.
I was trying something like below, but am really stuck what's the best approach...
$i = count($array); // gives me back the count of 3 which is correct
$n = 0;
foreach($array as $key=>values) {
foreach($values as $value) {
// do not how to proceed :(
}
}
You can call array_intersect with all the sub-arrays as arguments.
$common_values = call_user_func_array('array_intersect', $array);
Maybe you can affect your rows in some var and make what you want to do in your foreach
Like :
<?php
$width = 0;
$height = 0;
$color = 0 ;
$arrayBundleWidth = array();
$arrayBundleHeight = array();
$arrayBundleColor = array();
foreach ($array as $arrayRow){
$arrayBundleWidth = $arrayRow['width'];
$arrayBundleColor = $arrayRow['color'];
$arrayBundleHeight = $arrayRow['height'];
foreach ($arrayBundleWidth as $arrayBundleWidthtRow) {
# code...
#you got each index of your width array here
}
foreach ($arrayBundleHeight as $arrayBundleHeightRow) {
# code...
#you got each index of your height array here
}
foreach ($arrayBundleColor as $arrayBundleColorRow) {
# code...
#you got each index of your color array here
}
}
?>
Try it and tell me ? Is it what you want ?
Not sure if it's what you wanted to do !
Related
Please find below the code sample for adding repeated values inside inner array. Can anyone suggest an alternative way to add the values faster? The code will work with smaller arrays, but I want to add big arrays that contain huge amount of data. Also I want to increase execution time.
<?php
$testArry = array();
$testArry[0] = array(
"text" => "AB",
"count" => 2
);
$testArry[1] = array(
"text" => "AB",
"count" => 5
);
$testArry[2] = array(
"text" => "BC",
"count" => 1
);
$testArry[3] = array(
"text" => "BD",
"count" => 1
);
$testArry[4] = array(
"text" => "BC",
"count" => 7
);
$testArry[5] = array(
"text" => "AB",
"count" => 6
);
$testArry[6] = array(
"text" => "AB",
"count" => 2
);
$testArry[7] = array(
"text" => "BD",
"count" => 111
);
$match_key = array();
$final = array();
foreach ($testArry as $current_key => $current_array) {
$match_key = array();
foreach ($testArry as $search_key => $search_array) {
$key = '';
if ($search_array['text'] == $current_array['text']) {
$match_key[] = $search_key;
$key = $search_array['text'];
if (isset($final[$key])) {
$final[$key] += $search_array['count'];
} else {
$final[$key] = $search_array['count'];
}
}
}
for ($j = 0; $j < count($match_key); $j++) {
unset($testArry[$match_key[$j]]);
}
}
print_r($final);
?>
Anyway to add memory during the execution time?
Thank you.
One array_walk will be enough to solve your problem,
$final = [];
array_walk($testArry, function($item) use(&$final){
$final[$item['text']] = (!empty($final[$item['text']]) ? $final[$item['text']] : 0) + $item['count'];
});
print_r($final);
Output
Array
(
[AB] => 15
[BC] => 8
[BD] => 112
)
Demo
array_walk — Apply a user supplied function to every member of an array
array_map() - Applies the callback to the elements of the given arrays
array_key_exists() - Checks if the given key or index exists in the array
You can use array_walk and array_key_exists to iterate through the array element and sum the one which has text index same
$res = [];
array_map(function($v) use (&$res){
array_key_exists($v['text'], $res) ? ($res[$v['text']] += $v['count']) : ($res[$v['text']] = $v['count']);
}, $testArry);
I want to ask about compare 2 arrays with same key but different value.
I have 1 array master (arrayMaster) and 2 or more array data (arrayData1, arrayData2, and maybe could be more). These array data key will have exactly one of arrayMaster data key (I've done for this thing). For data example that I get:
arrayMaster = Array( [apple] => 1 [banana] => 2 [choco] => 1 [donut] => 2 [egg] => 1 )
arrayData1 = Array( [apple] => 8 [banana] => 2 [choco] => 1 )
arrayData2 = Array( [donut] => 5 [choco] => 2 [egg] => 3 )
(We can see that arrayData1 and arrayData2 contain a key from arrayMaster key.)
These arrays I want to compare and give a calculating method. If the array key at arrayData(n) found at arrayMaster, it will do a calculating data, let said it will sum each other.
So, the result is:
arrayResult1 = 1+8 (apple have 1 from master, apple have 8 from arrayData1), 2+2, 1+1
arrayResult2 = 2+5 (donut have 2 from master, donut have 5 from arrayData2), 1+2, 1+3
So I will have 2 new array (or more, depend on how much arrayData) that contain:
arrayResult1 = ([apple] => 9 [banana] => 4 [choco] => 2);
arrayResult2 = ([donut] => 7 [choco] => 3, [egg] => 4);
Anyone know how to do this? I’”ve tried array_intersect but it didn’t work.
Do something like this:
function doCalc($master, $slave) {
$results = array();
foreach( $slave as $key => $value ) {
if( !isset($master[$key]) ) {
$results[$key] = $value;
}
else {
$results[$key] = $master[$key] + $value;
}
}
return $results;
}
$arrayResult1 = doCalc($arrayMaster, $arrayData1);
$arrayResult2 = doCalc($arrayMaster, $arrayData2);
You can write something simpler like this..
function modifyArr(&$arr,$basearray) //<=-- See I am passing & (reference) so your original array will be modified
{
foreach($arr as $k=>$v)
{
if(array_search($k,$basearray)!==null)
{
$arr[$k]=$basearray[$k]+$arr[$k];
}
}
}
modifyArr($arrayData1,$arrayMaster); //<=-- Pass your 1st array
modifyArr($arrayData2,$arrayMaster); //<=-- Pass your 2nd array
Demonstration
Using these as examples:
arrayResult1 = 1+8 (apple have 1 from master, apple have 8 from arrayData1), 2+2, 1+1
arrayResult2 = 2+5 (donut have 2 from master, donut have 5 from arrayData2), 1+2, 1+3
Why not just do this:
// The main arrays for master & data values.
$arrayMaster = array('apple' => 1, 'banana' => 2, 'choco' => 1, 'donut' => 2, 'egg' => 1);
$arrayData1 = array('apple' => 8, 'banana' => 2, 'choco' => 1);
$arrayData2 = array('donut' => 5, 'choco' => 2, 'egg' => 3);
// Set a values to check array.
$values_to_check = array('apple', 'donut');
// Init the results array.
$results_array = array();
// Roll through the values to check.
foreach ($values_to_check as $value) {
// Check if the array key exists in '$arrayMaster'.
if (array_key_exists($value, $arrayMaster)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayMaster[$value];
// Check if the array key exists in '$arrayData1'.
if (array_key_exists($value, $arrayData1)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayData1[$value];
}
// Check if the array key exists in '$arrayData2'.
if (array_key_exists($value, $arrayData2)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayData2[$value];
}
}
}
// Roll through the results array and use 'array_sum' to get a sum of values.
foreach ($results_array as $results_key => $results_value) {
echo $results_key . ' : ' . array_sum($results_value) . '<br />';
}
But looking at your example, I am unclear on why you have separate arrays for $arrayData1 and $arrayData2 so here is the same code, but refactored to have nested arrays in $arrayData which should be more efficient:
// The main arrays for master & data values.
$arrayMaster = array('apple' => 1, 'banana' => 2, 'choco' => 1, 'donut' => 2, 'egg' => 1);
$arrayData = array();
$arrayData[] = array('apple' => 8, 'banana' => 2, 'choco' => 1);
$arrayData[] = array('donut' => 5, 'choco' => 2, 'egg' => 3);
// Set a values to check array.
$values_to_check = array('apple', 'donut');
// Init the results array.
$results_array = array();
// Roll through the values to check.
foreach ($values_to_check as $value) {
// Check if the array key exists in '$arrayMaster'.
if (array_key_exists($value, $arrayMaster)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayMaster[$value];
// Roll through the values to check.
foreach ($arrayData as $arrayData_value) {
// Check if the array key exists in '$arrayData1'.
if (array_key_exists($value, $arrayData_value)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayData_value[$value];
}
}
}
}
// Roll through the results array and use 'array_sum' to get a sum of values.
foreach ($results_array as $results_key => $results_value) {
echo $results_key . ' : ' . array_sum($results_value) . '<br />';
}
I have an array that is composed of information that looks like the following:
['Jay', 'Jay', 'Jay', 'Spiders', 'Dogs', 'Cats', 'John', 'John', 'John', 'Dogs', 'Cows', 'Snakes']
What I'm trying to do is remove duplicate entries but only if they occur right next to each other.
The correct result should look like the following:
['Jay', 'Spiders', 'Dogs', 'Cats', 'John', 'Dogs', 'Cows', 'Snakes']
I'm using PHP but any kind of logic would be able to help me out with this problem.
Here is some code I've tried so far:
$clean_pull = array();
$counter = 0;
$prev_value = NULL;
foreach($pull_list as $value) {
if ($counter == 0) {
$prev_value = $value;
$clean_pull[] = $value;
}
else {
if ($value != $pre_value) {
$pre_value = value;
}
}
echo $value . '<br>';
}
Francis, when I run the following code:
$lastval = end($pull_list);
for ($i=count($pull_list)-2; $i >= 0; $i--){
$thisval = $pull_list[$i];
if ($thisval===$lastval) {
unset($pull_list[$i]);
}
$lastval = $thisval;
}
# optional: reindex the array:
array_splice($pull_list, 0, 0);
var_export($pull_list);
, I get these results:
array ( 0 => 'NJ Lefler', 1 => 'Deadpool', 2 => 'NJ Lefler', 3 => 'Captain Universe: The Hero Who Could Be You', 4 => 'NJ Lefler', 5 => 'The Movement', 6 => 'NJ Lefler', 7 => 'The Dream Merchant', 8 => 'Nolan Lefler', 9 => 'Deadpool', 10 => 'Nolan Lefler', 11 => 'Captain Universe: The Hero Who Could Be You', 12 => 'Nolan Lefler', 13 => 'The Movement', 14 => 'Tom Smith', 15 => 'Deadpool', 16 => 'Tom Smith', 17 => 'Captain Universe: The Hero Who Could Be You', )
Your approach (a $prev_value variable) should work fine and you don't need a counter.
Your use of $counter is why your code doesn't work--the first half of the if statement is always executed because $counter is never incremented; and the second half just compares values. The only thing you need to do is compare the current value with the previous value and include the current value only if it differs (or remove it only if it's the same).
It's much easier to see this algorithm if you use functional reduction. Here is an example using array_reduce:
$a = array('Jay', 'Jay', 'Jay', 'Spiders', 'Dogs', 'Cats', 'John', 'John', 'John', 'Dogs', 'Cows', 'Snakes');
$na = array_reduce($a, function($acc, $item){
if (end($acc)!==$item) {
$acc[] = $item;
}
return $acc;
}, array());
var_export($na);
Note this comparison of var_export($a) (your original array) and var_export($na) (the result produced by the code):
$a = array ( $na = array (
0 => 'Jay', 0 => 'Jay',
1 => 'Jay', 1 => 'Spiders',
2 => 'Jay', 2 => 'Dogs',
3 => 'Spiders', 3 => 'Cats',
4 => 'Dogs', 4 => 'John',
5 => 'Cats', 5 => 'Dogs',
6 => 'John', 6 => 'Cows',
7 => 'John', 7 => 'Snakes',
8 => 'John', )
9 => 'Dogs',
10 => 'Cows',
11 => 'Snakes',
)
The array_reduce() method does exactly the same thing as the following code:
$na = array();
foreach ($a as $item) {
if (end($na)!==$item) {
$na[] = $item;
}
}
Instead of returning a copy of an array, you can also modify the array in-place using the same algorithm but starting from the end of the array:
$lastval = end($a);
for ($i=count($a)-2; $i >= 0; $i--){
$thisval = $a[$i];
if ($thisval===$lastval) {
unset($a[$i]);
}
$lastval = $thisval;
}
# optional: reindex the array:
array_splice($a, 0, 0);
var_export($a);
Keep track of the last element in the array, and skip adding the next element to your new array if you just added it.
Or, you can just check the last element in the array, and see if it's not the current element in your array:
$array = ['Jay', 'Jay', 'Jay', 'Spiders', 'Dogs', 'Cats', 'John', 'John', 'John', 'Dogs', 'Cows', 'Snakes'];
$new = array( array_shift( $array));
foreach( $array as $el) {
if( !($new[count($new) - 1] === $el)) {
$new[] = $el;
}
}
Assuming the array isn't so large that having a second one will cause a problem, the approach you described should work. Does it look like this?
$last = null;
$result = [];
foreach($arr as $item)
if($item !== $last)
$result[] = $last = $item;
Re: edit:
$pre_value and $prev_value aren't the same thing
$counter doesn't change
It looks like you tried to combine a counter approach and a "last" approach somehow.
Define a global variable glob.
pass the array:
if (array[i] == glob) then
remove array[i]
else
glob = array[i];
keep array[i];
I'm working on a leader board that pulls the top scorers into first, second, and third place based on points. Right now I'm working with a sorted array that looks like this (but could be of infinite length with infinite point values):
$scores = Array
(
["bob"] => 20
["Jane"] => 20
["Jill"] => 15
["John"] => 10
["Jacob"] => 5
)
I imagine I could use a simple slice or chunk, but I'd like to allow for ties, and ignore any points that don't fit into the top three places, like so:
$first = Array
(
["bob"] => 20
["Jane"] => 20
)
$second = Array
(
["Jill"] => 15
)
$third = Array
(
["John"] => 10
)
Any ideas?
$arr = array(
"Jacob" => 5,
"bob" => 20,
"Jane" => 20,
"Jill" => 15,
"John" => 10,
);
arsort($arr);
$output = array();
foreach($arr as $name=>$score)
{
$output[$score][$name] = $score;
if (count($output)>3)
{
array_pop($output);
break;
}
}
$output = array_values($output);
var_dump($output);
$first will be in $output[0], $second in $output[1] and so on.. Code is limited to 3 first places.
ps: updated to deal with tie on the third place
I would do something like:
function chunk_top_n($scores, $limit)
{
arsort($scores);
$current_score = null;
$rank = array();
$n = 0;
foreach ($scores as $person => $score)
{
if ($current_score != $score)
{
if ($n++ == $limit) break;
$current_score = $score;
$rank[] = array();
$p = &$rank[$n - 1];
}
$p[$person] = $score;
}
return $rank;
}
It sorts the array, then creates numbered groups. It breaks as soon as the limit has been reached.
You can do it with less code if you use the score as the key of the array, but the benefit of the above approach is it creates the array exactly how you want it the first time through.
You could also pass $scores by reference if you don't mind the original getting sorted.
Here's my go at it:
<?php
function array_split_value($array)
{
$result = array();
$indexes = array();
foreach ($array as $key => $value)
{
if (!in_array($value, $indexes))
{
$indexes[] = $value;
$result[] = array($key => $value);
}
else
{
$index_search = array_search($value, $indexes);
$result[$index_search] = array_merge($result[$index_search], array($key => $value));
}
}
return $result;
}
$scores = Array(
'bob' => 20,
'Jane' => 20,
'Jill' => 15,
'John' => 10,
'Jacob' => 5
);
echo '<pre>';
print_r(array_split_value($scores));
echo '</pre>';
?>
Suppose you have an array "value => timestamp". The values are increasing with the time but they can be reset at any moment.
For example :
$array = array(
1 => 6000,
2 => 7000,
3 => 8000,
7 => 9000,
8 => 10000,
9 => 11000,
55 => 1000,
56 => 2000,
57 => 3000,
59 => 4000,
60 => 5000,
);
I would like to retrieve all the missing values from this array.
This example would return :
array(4,5,6,58)
I don't want all the values between 9 and 55 because 9 is newer than the other higher values.
In real condition the script will deal with thousands of values so it need to be efficient.
Thanks for your help!
UPDATE :
The initial array can be ordered by timestamps if it is easier for the algorithm.
UPDATE 2 :
In my example the values are UNIX timestamps so they would look more like this : 1285242603 but for readability reason I simplified it.
Here’s another solution:
$prev = null;
$missing = array();
foreach ($array as $curr => $value) {
if (!is_null($prev)) {
if ($curr > $prev+1 && $value > $array[$prev]) {
$missing = array_merge($missing, range($prev+1, $curr-1));
}
}
$prev = $curr;
}
You can do the following:
Keep comparing adjacent array keys. If
they are consecutive you do nothing.
If they are not consecutive then you
check their values, if the value has
dropped from a higher value to a
lower value, it means there was a
reset so you do nothing.
If the value has not dropped then it
is a case of missing key(s). All the
numbers between the two keys(extremes
not included) are part of the result.
Translated in code:
$array = array( 1 => 6000, 2 => 7000, 3 => 8000, 7 => 9000, 8 => 10000,
9 => 11000,55 => 1000, 56 => 2000, 57 => 3000, 59 => 4000,
60 => 5000,);
$keys = array_keys($array);
for($i=0;$i<count($array)-1;$i++) {
if($array[$keys[$i]] < $array[$keys[$i+1]] && ($keys[$i+1]-$keys[$i] != 1) ) {
print(implode(' ',range($keys[$i]+1,$keys[$i+1]-1)));
print "\n";
}
}
Working link
This gives the desired result array(4,5,6,58):
$previous_value = NULL;
$temp_store = array();
$missing = array();
$keys = array_keys($array);
for($i = min($keys); $i <= max($keys); $i++)
{
if(!array_key_exists($i, $array))
{
$temp_store[] = $i;
}
else
{
if($previous_value < $array[$i])
{
$missing = array_merge($missing, $temp_store);
}
$temp_store = array();
$previous_value = $array[$i];
}
}
var_dump($missing);
Or just use Gumbo's very smart solution ;-)