I am comparing each element of array with every other element of array and if two elements have the same source/target, target/source I merge the inner array with employees e.g.
0=> source - 3 target - 4 officers => 0 - 'Aberdeen Asset Management PLC'
1=> source - 3 target - 4 officers => 0 - 'whatever'
it would be merged to
0=> source - 3 target - 4 officers => 0 - 'Aberdeen Asset Management PLC', 1 - 'whatever'
Here is how the data looks like:
My code is really inefficient with 1000 on more rows to go through the execution takes about 90 seconds which is unacceptable for this sort of thing.
foreach ($edges as $i => &$edge) {
for ($j = $i + 1; $j < count($edges); $j++) {
if ($edge['source'] == $edges[$j]['source'] && $edge['target'] == $edges[$j]['target']) {
foreach ($edges[$j]['officers'] as $officer) {
array_push($edge['officers'], $officer);
}
array_splice($edges, $j, 1);
}
}
}
The solution using array_search, array_keys, array_slice and array_merge functions:
// an exemplary array
$edges = [
0 => ['source' => 3, 'target' => 4, 'officers' => ['Aberdeen Asset Management PLC']],
1 => ['source' => 3, 'target' => 4, 'officers' => ['whatever']],
3 => ['source' => 4, 'target' => 7, 'officers' => ['Jason']],
4 => ['source' => 4, 'target' => 5, 'officers' => ['John']],
5 => ['source' => 4, 'target' => 7, 'officers' => ['Bourne']]
];
foreach ($edges as $k => &$v) {
$next_slice = array_slice($edges, array_search($k, array_keys($edges)) + 1);
foreach ($next_slice as $key => $item) {
if ($item['source'] == $v['source'] && $item['target'] == $v['target']) {
$v['officers'] = array_merge($v['officers'], $item['officers']);
unset($edges[$k + $key + 1]);
}
}
}
print_r($edges);
DEMO link
I think you should do this (updated):
// we will have new array with officers
$new_items = array();
foreach ($edges as $edge) {
// create unique keys for `source-target` and `target-source` pairs
$source_target = $edge['source'] . ':' . $edge['target'];
$target_source = $edge['target'] . ':' . $edge['source'];
// check if unique keys exists in `new_items`
if (!isset($new_items[$source_target]) && !isset($new_items[$target_source])) {
// if unique key doesn't exist - create a new one
$new_items[$source_target] = $edge;
} elseif (isset($new_items[$source_target])) {
// if unique key exists `$source_target` - add an officer to it
$new_items[$source_target]['officers'][] = $edge['officers'][0];
} else {
// if unique key exists `$target_source` - add an officer to it
$new_items[$target_source]['officers'][] = $edge['officers'][0];
}
}
// for returning to numeric indexes use `array_values`
$new_items = array_values($new_items);
Related
I'm trying to output [device_id] of the least frequent [device_ip_isp] from this array.
Also, If the array only has two SharedDevice Object available, and having different [device_ip_isp], it should output the 2nd SharedDevice Object's [device_id]
array (
0 =>
SharedDevice::__set_state(array(
'device_no' => 1,
'device_id' => '82',
'device_ip_isp' => 'Verizon Fios',
)),
1 =>
SharedDevice::__set_state(array(
'device_no' => 2,
'device_id' => '201',
'device_ip_isp' => 'Spectrum',
)),
2 =>
SharedDevice::__set_state(array(
'device_no' => 3,
'device_id' => '312',
'device_ip_isp' => 'Verizon Fios',
)),
3 =>
SharedDevice::__set_state(array(
'device_no' => 4,
'device_id' => '9715',
'device_ip_isp' => 'Verizon Fios',
)),
4 =>
SharedDevice::__set_state(array(
'device_no' => 5,
'device_id' => '11190',
'device_ip_isp' => 'Verizon Fios',
)),
)
The output should be 201 because "Spectrum" is the least frequent.
I tried the following and had issues:
I'm not sure how I can sort the object variables before comparing to find the least frequent.
/*
$user->getUser_devices() will output the array shown above.
*/
leastFrequent($user->getUser_devices(), 5);
function leastFrequent($arr, $n){
// find the min frequency
// using linear traversal
$min_count = $n + 1;
$res = -1;
$curr_count = 1;
for ($i = 1; $i < $n; $i++) {
if ($arr[$i]['device_ip_isp'] == $arr[$i - 1]['device_ip_isp']) {
$curr_count++;
} else {
if ($curr_count < $min_count) {
$min_count = $curr_count;
$res = $arr[$i - 1]['device_id'];
}
$curr_count = 1;
}
}
// If last element is
// least frequent
if ($curr_count < $min_count) {
$min_count = $curr_count;
$res = $arr[$n - 1]['device_id'];
}
return $arr[$n]$res['device_id'];
}
Ok, below is the explanation of the snippet inside out.
array_column to get all the device_ip_isp values in a single array.
array_count_values to get the frequency of each value.
array_reverse to reverse the count frequency array since you need the latest share device ID incase of count collision for a minimum count value.
min to get the lowest value among all the frequency counts.
array_search to get the key of the first frequency min element.
In the end, we reverse the input array to immediate return the device IP the moment we find the key from the above step matching the current device_ip_isp.
Snippet:
<?php
function getLeastFrequentElement($arr){
$freqs = array_reverse(array_count_values(array_column($arr, 'device_ip_isp')));
$deviceIPISP = array_search(min($freqs), $freqs);
foreach(array_reverse($arr) as $sharedDevice){
if($sharedDevice->device_ip_isp === $deviceIPISP){
return $sharedDevice->device_id;
}
}
throw new Exception("No shared object found!");
}
echo getLeastFrequentElement($arr);
Online Demo
I have following code that removes adjacent duplicates from the $myArray
<?php
$myArray = array(
0 => 0,
1 => 0,
2 => 1,
5 => 1,
6 => 2,
7 => 2,
8 => 2,
9 => 0,
10 => 0,
);
$previtem= NULL;
$newArray = array_filter(
$myArray,
function ($currentItem) use (&$previtem) {
$p = $previtem;
$previtem= $currentItem;
return $currentItem!== $p ;
}
);
echo "<pre>";
print_r($newArray);
?>
It works perfectly fine, but I have to change a condition bit for value 2. That means for other values we can pick first occurrence and ignore the others. But for 2, we need to pick last occurrence and ignore others.
So required output is
Array
(
[0] => 0 //first occurrence of 0 in $myArray
[2] => 1 //first occurrence of 1 in $myArray
[8] => 2 //last occurrence of 2 in the $myArray
[9] => 0 //first occurrence of 0 in $myArray
)
How to modify my code to achieve above result??
In reality I have multidimensional array, but for better explanation I have used single dimensional array here in the question.
UPDATE
My actual array is
$myArray = array(
0 => array("Value"=>0, "Tax" => "11.00"),
1 => array("Value"=>0, "Tax" => "12.00"),
2 => array("Value"=>1, "Tax" => "13.00"),
5 => array("Value"=>1, "Tax" => "14.00"),
6 => array("Value"=>2, "Tax" => "15.00"),
7 => array("Value"=>2, "Tax" => "16.00"),
8 => array("Value"=>2, "Tax" => "17.00"),
9 => array("Value"=>0, "Tax" => "18.00"),
10 => array("Value"=>0, "Tax" => "19.00"),
);
And my actual code
$previtem= NULL;
$newArray = array_filter(
$myArray,
function ($currentItem) use (&$previtem) {
$p["Value"] = $previtem["Value"];
$previtem["Value"] = $currentItem["Value"];
return $currentItem["Value"]!== $p["Value"] ;
}
);
Thanks
This should do what you are looking for.
function array_filter($a) {
$na = array();
$first = true;
$p = null;
$wantlast = false;
foreach ($a as $v) {
if ($wantlast) {
($v != $p) ? $na[] = $p: null;
}
$wantlast = ($v == 2) ? true : false;
if (!$wantlast) {
(($v != $p) || ($first))? $na[] = $v : null;
}
$p = $v;
$first = false;
}
return $na;
}
$myArray = array(
0 => 0,
1 => 0,
2 => 1,
5 => 1,
6 => 2,
7 => 2,
8 => 2,
9 => 0,
10 => 0,
);
$previtem= NULL;
$newArray = array_filter(
$myArray,
function ($currentItem, $key) use (&$previtem,$myArray) {
$p = $previtem;
if($currentItem != 2){
$previtem = $currentItem;
}else{
$lastkey = array_search(2,(array_reverse($myArray, true)));
if($key != $lastkey)
$currentItem = $previtem;
}
return $currentItem!== $p ;
}, ARRAY_FILTER_USE_BOTH
);
echo "<pre>";
print_r($newArray);
This is almost similar to my other question which is related to the same project I'm working on.. Link to my other question
but in this case the array is different as follow:
Array
(
[2014-08-01 11:27:03] => 2
[2014-08-01 11:52:57] => 2
[2014-08-01 11:54:49] => 2
[2014-08-02 11:59:54] => 4
[2014-08-02 12:02:41] => 2
[2014-08-05 12:09:38] => 4
[2014-08-07 12:23:12] => 3
[2014-08-07 12:25:18] => 3
// and so on...
)
That is my output array and in order to get that array I had to do some miracles... anyway, so based on that array I have to sum the value for each key date and build an array something like this...
Array
(
[2014-08-01] => 6
[2014-08-02] => 6
[2014-08-05] => 4
[2014-08-07] => 6
// and so on...
)
That last array will be use to build graphs with morrisonJS, what I have is this:
$res_meno = array();
foreach ($sunArr as $keys => $values) {
$arrays= explode(" ",$sumArr[$keys]);
$res_meno[] = $arrays[0];
}
$vals_char2 = array_count_values($res_meno);
That is my attempt to build my last array but is not working...
any help would be greatly appreciated!
Thank you for taking the time.
Try this code
<?php
$arr = array(
"2014-08-01 11:27:03" => 2,
"2014-08-01 11:52:57" => 2,
"2014-08-01 11:54:49" => 2,
"2014-08-02 11:59:54" => 4,
"2014-08-02 12:02:41" => 2,
"2014-08-05 12:09:38" => 4,
"2014-08-07 12:23:12" => 3,
"2014-08-07 12:25:18" => 3
);
$new_array = array();
foreach($arr as $k => $v){
$date = reset(explode(" ", $k));
if(isset($new_array[$date])){
$new_array[$date] += $v;
}
else{
$new_array[$date] = $v;
}
}
print_r($new_array);
?>
DEMO
$sunArr = array
(
"2014-08-01 11:27:03" => 2,
"2014-08-01 11:52:57" => 2,
"2014-08-01 11:54:49" => 2,
"2014-08-02 11:59:54" => 4,
"2014-08-02 12:02:41" => 2,
"2014-08-05 12:09:38" => 4,
"2014-08-07 12:23:12" => 3,
"2014-08-07 12:25:18" => 3,
);
$res_meno = array();
foreach ($sunArr as $keys => $values) {
$arrays= explode(" ",$keys);
if(isset($res_meno[$arrays[0]]))
{
$res_meno[$arrays[0]] = $res_meno[$arrays[0]] + $values;
}
else
{
$res_meno[$arrays[0]] = $values;
}
}
print_r($res_meno);
exit;
Try this, i think it might fix the problem
Try this PHP Code You Can test here
$sunArr = Array
(
'2014-08-01 11:27:03' => 2,
'2014-08-01 11:52:57' => 2,
'2014-08-01 11:54:49' => 2,
'2014-08-02 11:59:54' => 4,
'2014-08-02 12:02:41' => 2,
'2014-08-05 12:09:3' => 4,
'2014-08-07 12:23:12' => 3,
'2014-08-07 12:25:18' => 3
);
$key = 0;
$res_meno = array();
foreach ($sunArr as $keys => $values)
{
$ar= explode(" ", $keys);
if( $key == $ar[0] )
{
$res_meno[$key] = $sunArr[$keys] + $res_meno[$key];
}
else
{
$key = $ar[0];
$res_meno[$key] = $values;
}
}
echo '<pre>';
print_r($res_meno);
die;
Where does the first array come from? If it's from a SQL database, it's better to create a query that returns the aggregated array.
Otherwise no need to use array_key_values for that:
$res_meno = array();
foreach ($sumArr as $keys => $values) {
$key = substr($keys, 0, 10);
$res_meno[$key] = (empty($res_meno[$key]) ? 0 : $res_meno[$key]) + $values;
}
Here is a solution which uses a callback. Not to use loops is often better!
$sunArr = array(
'2014-08-01 11:27:03' => 3,
'2014-08-01 11:27:05' => 5,
'2013-09-01 11:01:05' => 1
);
$res = array();
function map($item, $key, &$result)
{
$result[current(explode(" ", $key))] += $item;
}
array_walk($sunArr, "map", &$res);
var_dump($res);
You can test it here on codepad.
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];