PHP and 2 multidimensional array compare based on two key values - php

I have two multidimensional arrays like this:
$original = Array (
[0] => Array
(
[time] => 1364690340
[memberid] => 90
[type] => single
)
[1] => Array
(
[time] => 1364690341
[memberid] => 92
[type] => fixed
)
[2] => Array
(
[time] => 1364690342
[memberid] => 96
[type] => single
)
)
and second one like this
$new = Array (
[0] => Array
(
[time] => 1364825750
[memberid] => 90
[type] => single
)
[1] => Array
(
[time] => 1364825751
[memberid] => 92
[type] => single
)
[2] => Array
(
[time] => 1364825752
[memberid] => 96
[type] => single
)
[3] => Array
(
[time] => 1364825753
[memberid] => 111
[type] => single
)
)
My problem is: I want to search $original array for matches based on memberid and type keys and if memberid and type ARE NOT the same -> I want to remove that array from $original array. So in this case I want to keep [0] Array and [2] Array as in $new array I have same memberid and same type as in original, but I would want to remove [1] Array as memberid is the same, but type is different. So my final $original array will look like this:
$original = Array (
[0] => Array
(
[time] => 1364690340
[memberid] => 90
[type] => single
)
[1] => Array
(
[time] => 1364690342
[memberid] => 96
[type] => single
)
)

Here you go, just tested it and it works as expected.
// Presuming your two arrays are still called $new & $original
$original = array(); // your data
$new = array(); // your data
$newArray = array();
foreach($original AS $key => $val){
$newArray[$val['memberid'] . '-' . $val['type']] = $val;
}
$original = array();
foreach($new AS $key => $val){
if(isset($newArray[$val['memberid'] . '-' . $val['type']])){
$original[] = $newArray[$val['memberid'] . '-' . $val['type']];
}
}
print_r($original);

Without making any assumptions about your data, here's an inefficient solution, O(m * n) if m and n are the lengths of your arrays:
$new_original = array();
foreach ($original as $elem) {
// let's see if $new has something with the same type and memberid
foreach ($new as $candidate) {
if ($candidate['type'] == $elem['type'] &&
$candidate['memberid'] == $elem['memberid']) {
// it does! let's keep $elem
$new_original[] = $elem;
}
}
}
// reassign it to $original if desired
$original = $new_original;
However, it would be much cooler to do more efficient lookups. For example, if we can assume there is at most one element with a given memberid in $new:
// turn $new into a map
$new_as_map = array();
foreach ($new as $candidate) {
$new_as_map[$candidate['memberid']] = $candidate;
}
$new_original = array();
foreach ($original as $elem) {
if (isset($new_as_map[$elem['memberid']])) {
$candidate = $new_as_map[$elem['memberid']];
if ($candidate['type'] == $elem['type']) {
$new_original[] = $elem;
}
}
}
// reassign it to $original if desired
$original = $new_original;

Related

Odd PHP behaviour when generating list of array values

I have a multidimensional PHP array of the following form:
Array
(
[0] => Array
(
[id] => 45
[date] => 2013-05-16
)
[1] => Array
(
[id] => 30
[date] => 2013-12-10
)
[2] => Array
(
[id] => 26
[date] => 2014-03-27
)
[3] => Array
(
[id] => 34
[date] => 2014-03-27
)
)
I am trying to generate a list of the [id] values, separated by commas, using the following PHP code:
foreach ($my_array as $key => $value) {
if ($key == 0) {
$id_list = $value[id];
}
if ($key !== 0 ) {
$id_list .= "," . $value[id];
}
}
I was hoping this would return
45,30,26,34
...but for some reason it returns
45,30,26,26
i.e. the penultimate ID is duplicated and the final ID is missed off. I have been staring at this for a while now but I can't see where I'm going wrong. Have I missed something obvious?
The better solution would be to not use those if() at all:
$ids = array();
foreach($arr as $val) {
$ids[] = $val['id'];
}
$id_str = implode(',', $ids);

Create new array from another

i have an array:
Array
(
[users] => Array
(
[101] => Array
(
[odata] => Array
(
[0] => 2
[1] => 1
[2] => 1
[3] => 1
)
)
[200] => Array
(
[odata] => Array
(
[0] => 2
[1] => 1
[2] => 1
[3] => 0
)
)
)
[rjad] => Array
(
[2] => Array
(
[0] => red
[1] => blue
[2] => green
)
)
)
in this array [rjad] key = [odata] key, and [odata] value = second key in [rjad].
What i want is to create new array from old one with user ids values in second array:
like this:
[rjad] => Array
(
[2] => Array
(
[0] => red
[1] => Array
(
[blue] => Array
(
[0] => 101
[1] => 200
)
[2] => green
)
)
Struggling already 3 hours with no success. Any ideas how to get it are very wellcome.
Image do explain relatinships
http://imageshack.us/photo/my-images/818/phparray.jpg/
I'd seriously rethink your structure, but here's a working (if ugly) solution
foreach ($users as $userId => $user) {
foreach ($user['odata'] as $key => $value) {
if (isset($rjad[$key][$value])) {
if (!is_array($rjad[$key][$value])) {
$colour = $rjad[$key][$value];
$rjad[$key][$value] = array();
$rjad[$key][$value][$colour] = array();
} else {
reset($rjad[$key][$value]);
$colour = key($rjad[$key][$value]);
}
$rjad[$key][$value][$colour][] = $userId;
}
}
}
Working demo -> http://codepad.viper-7.com/IEcpvU
Based on comments seems you may want a separate array, which is easily solved
// copy the array and act on it instead of directly on $rjad
$result = $rjad;
foreach ($users as $userId => $user) {
foreach ($user['odata'] as $key => $value) {
if (isset($result[$key][$value])) {
if (!is_array($result[$key][$value])) {
$colour = $result[$key][$value];
$result[$key][$value] = array();
$result[$key][$value][$colour] = array();
} else {
reset($result[$key][$value]);
$colour = key($result[$key][$value]);
}
$result[$key][$value][$colour][] = $userId;
}
}
}
Your question isn't entirely clear - what is the relationship between rjad...blue and those user accounts from the other array? Is item 0 in the odata arrays the default colour?

list duplicates in PHP Array

i have a new problem and my mind is burning, i have an array in php
$test = array();
Array
(
[0] => Array
(
[account] => 14319896
[value] => 725.57
[id] => 280
)
[1] => Array
(
[account] => 163157
[value] => -723.57
[id] => 283
)
[2] => Array
(
[account] => 163157
[value] => 723.57
[id] => 284
)
[3] => Array
(
[account] => 161817
[value] => -723.57
[id] => 285
)
)
i need the accounts, they are more than one in this array, in this example i need $test[1][id] and $test[2][id]
have you an idea? i have no idea more at this time.
Thanks for your help.
Use the account number as key in a new array, count each entry and then take the items with a count > 1
$dupes = array();
foreach($array as $account) {
++$dupes[$account['account']];
}
$dupes = array_filter($dupes, function($count) { return $count > 1; });
Editing to answer the comments below the question …
If you want the IDs (or keys) of the duplicates, do not store the count directly, but use another array instead.
$dupes = array();
foreach($array as $key => $account) {
if(!array_key_exists($account, $dupes))
$dupes[$account['account']] = array();
$dupes[$account['account']][] = $account['id']; // or: = $key
}
$dupes = array_filter($dupes, function($ids) { return count($ids) > 1; });
You should change your architecture to have a associative array where keys are account number organized like that :
Array
(
[14319896] => Array
(
[0]=>Array(
[value] => 725.57
[id] => 280
)
)
[163157] => Array
(
[0]=>Array(
[value] => -723.57
[id] => 283
)
[1]=>Array(
[value] => 723.57
[id] => 284
)
)
[161817] => Array
(
[0]=>Array(
[value] => -723.57
[id] => 285
)
)
)
$dupes = array();
foreach($array as $key => $account) {
$dupes[$account['account']][] = array($account['id'],$account['value']);
}
Whith that architecture you can get everything you want thanks to array_filter :
$dups = array_filter($dupes, function($account){ return count($account)>1;});

Arrange PHP Multidimensional Array By Inner Index

How to arrange this array by last inner index ( 0, 1, 2 ) and get the value of the last inner index as the value of each second index:
Array
(
[text] => Array
(
[grid] => Array
(
[0] => 3
[1] => 4
[2] => 5
)
[image] => Array
(
[0] =>
[1] =>
[2] =>
)
[align] => Array
(
[0] => left
[1] => right
[2] => left
)
[title] => Array
(
[0] =>
[1] =>
[2] =>
)
[content] => Array
(
[0] =>
[1] =>
[2] =>
)
)
)
And have the results as below:
Array
(
[text] => Array
(
[0] => Array
(
[grid] => 3
[image] =>
[align] => left
[title] =>
[content] =>
)
[1] => Array
(
[grid] => 4
[image] =>
[align] => right
[title] =>
[content] =>
)
[2] => Array
(
[grid] => 5
[image] =>
[align] => left
[title] =>
[content] =>
)
)
)
This will do the work
function restructure($arr){
$newArr = array();
foreach($arr as $k => $v){
foreach($v as $k1 => $v1){
foreach($v1 as $k2 => $v2){
$newArr[$k][$k2][$k1] = $v2;
}
}
}
return $newArr;
}
As SiGanteng suggested, i dont see other ways than a for/foreach loop:
function buildArray($source, $key = false)
{
// Build the new array
$new_array = array();
// Define groups
$groups = $key === false ? array_keys($source) : array($key);
foreach($groups AS $group)
{
// Get the keys
$keys = array_keys($array[$group]);
// Count the values
$num_entries = count($array[$group][$keys[0]]);
for($i = 0; $i < $num_entries; $i++)
{
foreach($keys AS $key)
{
$new_array[$group][$i][$key] = $array[$group][$key][$i];
}
}
}
return $new_array;
}
This allow you to define the key you need to build; If not specified, the function build the array for every key.
This should work.
function formatit($arr) {
$new = array();
foreach($arr as $k=>$v) {
foreach($v as $k1=>$v1) {
$new[$k1][$k] = $v1;
}
}
return $new;
}
Tested. Call it as
$arr['text'] = formatit($arr['text']);
http://ideone.com/rPzuR

How to group multidimensional array by sub-array value in and reassign keys in PHP

I looked at all the similar questions and samples (there are many) but still can't get this to work (though I think I am close).
I have an array of employee schedules pulled from a text file...
schedule.txt:
123,Joe,20120208,0845,1645
123,Joe,20120209,0800,1600
456,Sue,20120208,0900,1700
456,Sue,20120209,0700,1500
...
My code to generate the array is:
$schedule = file_get_contents('./schedule.txt');
$s = explode("\n", $schedule);
for ($i = 0; $i < count($s); $i++) {
$s[$i] = explode(",", $s[$i]);
}
print_r($s);
Output is:
Array
(
[0] => Array
(
[0] => 123
[1] => Joe
[2] => 20120208
[3] => 0845
[4] => 1645
)
[1] => Array
(
[0] => 123
[1] => Joe
[2] => 20120209
[3] => 0800
[4] => 1600
)
[2] => Array
(
[0] => 456
[1] => Sue
[2] => 20120208
[3] => 0900
[4] => 1700
)
[3] => Array
(
[0] => 456
[1] => Sue
[2] => 20120209
[3] => 0700
[4] => 1500
)
)
I am instead trying to group employees by Id in a new multidimensional array with output like this:
Array
(
[123] => Array
(
[0] => Array
(
[0] => Joe
[1] => 20120208
[2] => 0845
[3] => 1645
)
[1] => Array
(
[0] => Joe
[1] => 20120209
[2] => 0800
[3] => 1600
)
)
[456] => Array
(
[0] => Array
(
[0] => Sue
[1] => 20120208
[2] => 0900
[3] => 1700
)
[1] => Array
(
[0] => Sue
[1] => 20120209
[2] => 0700
[3] => 1500
)
)
)
I cannot for the life of me wrap my head around how to change my existing array into this new (different) output...
I am trying this but getting nowhere:
$newArr = array();
foreach($s as $k => $v) {
if(!isset($newArr[$v[0]])) {
$newArr[$v[0]] = array();
}
$newArr[$v[0]][] = array($v[0]);
}
Though my output is now:
Array
(
[123] => Array
(
[0] => Array
(
[0] => 123
)
[1] => Array
(
[0] => 123
)
)
[456] => Array
(
[0] => Array
(
[0] => 456
)
[1] => Array
(
[0] => 456
)
)
)
Any thoughts? I know I am missing something in my code around the line:
$newArr[$v[0]][] = array($v[0]);
I tried changing it to:
$newArr[$v[0]][] = array(0 => $v[1], 1 => $v[2], 2 => $v[3], 3 => $v[4]);
which gives my the right output, but I now get undefined offset errors. Plus, if the number of keys in the sub array changes, this code is now limited to the 4 I explicitly entered...
this should be enough, if I understood you right :)
$lines = file('./schedule.txt');
$employees = array();
foreach ($lines as $line)
{
$chunks = explode(',', $line);
$employees[$chunks[0]][] = array_slice($chunks, 1);
}
print_r($employees);
There is a function called fgetcsv to easily grab comma separated values. No need to do it yourself.
This code also solves your problem and properly handles blank lines:
if (($handle = fopen("schedules.csv", "r")) !== FALSE) {
$schedules = array();
while (($data = fgetcsv($handle)) !== FALSE) {
if ($data[0] !== null) { //blank lines return an array containing null
$schedules[$data[0]][] = array_slice($data, 1);
}
}
fclose($handle);
//do what you need to
} else {
// file failed to open
}
Note that I named the file .csv instead of .txt. I'd recommend that you save things that are comma separated values as .csv files. Maybe even define what each column is in the file as well.
<?php
//read the file into an array with each line being an entry
$schedule = file('./schedule.txt');
//empty array
$s = array();
//loop through file lines
foreach($schedule as $row){
//explode on comma
$row = explode(",", trim($row));
//if the id doesn't exist yet...
if(!isset($s[$row[0]])){
//...make it an empty array
$s[$row[0]] = array();
}
//add the row under the id
$s[$row[0]][] = $row;
}
print_r($s);
?>
You can use fscanf:
$handle = fopen('./schedule.txt', 'r');
$employees = array();
while ($line = fscanf($handle, '%d,%s')) {
$employees[$line[0]][] = explode(',', $line[1]);
}
fclose($handle);
print_r($employees);

Categories