How can match two array in php - php

I have two array:
One Array
$workingDays = ['2019-11-01','2019-11-02','2019-11-03','2019-11-04'];
Other Array
$doneWork = array(
array(
'id' => 1,
'date' => '2019-11-01',
'work' => 'done'
),
array(
'id' => 1,
'date' => '2019-11-02',
'work' => 'done'
),
array(
'id' => 1,
'date' => '2019-11-04',
'work' => 'done'
)
);
My Question: How can check which date not exist in $doneWork array

You'd start by extracting the dates from $doneWork using array_map.
$doneWork = [
[
'id' => 1,
'date' => '2019-11-01',
'work' => 'done',
],
[
'id' => 1,
'date' => '2019-11-02',
'work' => 'done',
],
[
'id' => 1,
'date' => '2019-11-04',
'work' => 'done',
],
];
$doneWorkDays = array_map(function ($element) {
return $element['date'];
}, $doneWork);
print_r($doneWorkDays);
Will print:
Array ( [0] => 2019-11-01 [1] => 2019-11-02 [2] => 2019-11-04 )
Then check which elements in $workingDays are not in such array, using array_diff
$diff = array_diff($workingDays, $doneWorkDays);
print_r($diff);
Will print:
Array ( [2] => 2019-11-03 )
Pay attention, the result gives you not only the elements but also their index in the original array. If you don't care about these, use instead:
print_r(array_values($diff));
Why would anyone need such index? Well, perhaps you could need to report not only how many days were missed but also check if two missing elements are adjacent.
(the indexes are relevant only for the array you're comparing against. It doesn't matter in what position they appear in $doneWork )
Edit:
You say you need the results to be in "doneWork" format, which is an associative array with id (always zero), date and work (always 'absent').
Let's say your workin days are now
$workingDays = [
'2019-11-01',
'2019-11-02',
'2019-11-03',
'2019-11-04',
'2019-11-05'
];
So there are two missing days. Again, array map to the rescue:
// from previous answer
$diff = (array_diff($workingDays, $doneWorkDays));
// map each missing date to a doneWork array
$diff_assoc = array_values(
array_map(function($date) {
return [
'id' => 0,
'date' => $date,
'work' => 'absent'
];
},$diff)
);
That will return
Array
(
[0] => Array
(
[id] => 0
[date] => 2019-11-03
[work] => absent
)
[1] => Array
(
[id] => 0
[date] => 2019-11-05
[work] => absent
)
)
Again, note I'm wrapping the result in array_values because you need a plain array as result instead of:
Array
(
[2] => Array
(
[id] => 0
[date] => 2019-11-03
[work] => absent
)
[4] => Array
(
[id] => 0
[date] => 2019-11-05
[work] => absent
)
)

$nonExistingDates = [];
$doneWorkDays = [];
foreach($doneWork as $work) {
$doneWorkDays[] = $work['date'];
}
$nonExistingDates = array_diff($workingDays, $doneWorkDays);
// optional, removes duplicate dates
$nonExistingDates = array_unique($nonExistingDates);

Related

How to copy items to existing array

I'm new in PHP. I have reviewed some other threads about the array combination but I couldn't found the answer.
For example the first array
array (
'date' => '01.06.2019',
'day' => 'Saturday',
)
Second array
array (
0 =>
array (
'id' => 10,
'name' => 'Mj phooi',
),
)
Expected result
array (
'date' => '01.06.2019',
'day' => 'Saturday',
'id' => 10,
'name' => 'Mj phooi',
)
I did try the array_combine and array_merge_recursive but it doesn't work. The closure result I tried is like $result = array_merge($arr,$temp);. It combined two arrays but there have two arrays inside which not match with the expected result.
You are almost there, you could use array_merge but the array in the $temp is a nested array so you might take the first index 0:
$arr = [
'date' => '01.06.2019',
'day' => 'Saturday',
];
$temp = [
[
'id' => 10,
'name' => 'Mj phooi',
]
];
print_r(array_merge($arr, $temp[0]));
Result:
Array
(
[date] => 01.06.2019
[day] => Saturday
[id] => 10
[name] => Mj phooi
)
See a php demo
Note that an array can not have duplicate keys so if they have the same keys the last will override the existing key.

PHP usort collections with varying attributes

I have two identical arrays:
$array1 = array(
array(
'start' => 1,
'value' => 10
),
array(
'start' => 8,
'value' => 4
),
array(
'start' => 4,
'value' => 8
),
array(
'value' => 5,
)
);
$array2 = array(
array(
'start' => 1,
'value' => 10
),
array(
'start' => 8,
'value' => 4
),
array(
'start' => 4,
'value' => 8
),
array(
'value' => 5,
)
);
I need to merge and sort them in ascending order:
$array1 = array_merge($array1, $array2);
usort($array1, function($value1, $value2) {
if (!array_key_exists('start', $value1) || !array_key_exists('start', $value2)) {
return 0;
}
return $value1['start'] - $value2['start'];
});
However, this doesn't work, and the ordering is incorrect:
Array
(
[0] => Array
(
[start] => 4
[start] => 8
)
[1] => Array
(
[start] => 8
[value] => 4
)
[2] => Array
(
[amount] => 5
)
[3] => Array
(
[start] => 1
[value] => 10
)
[4] => Array
(
[value] => 5
)
[5] => Array
(
[start] => 1
[value] => 10
)
[6] => Array
(
[start] => 4
[value] => 8
)
[7] => Array
(
[start] => 8
[value] => 4
)
)
It should ideally place all items without a start attribute to the start of the array and all items with a start attribute following those in ascending order.
If I remove the arrays that contain no start attribute, it seems to work perfectly. But I need to keep those items without a start attribute. Is there anything I can do with my sort to go around this issue without going through the merged array, removing those that have no start and replacing them after the sort? Ideally I'd love to understand what is happening here to make it fail.
To place the elements without an start key at the front, you have to handle them diffrently in your compare function.
You could try something like this
usort($array1, function($value1, $value2) {
if (!isset($value1['start']) && !isset($value2['start'])) {
return 0;
} else if (!isset($value1['start'])) {
return -1;
} else if (!isset($value2['start'])) {
return 1;
}
return $value1['start'] - $value2['start'];
});

PHP Replace Array Values

I have 2 multidimensional arrays that I am working with:
$arr1 =
Array
([type] => characters
[version] => 5.6.7.8
[data] => Array
([Char1] => Array
([id] => 1
[name] =>Char1
[title] =>Example
[tags] => Array
([0] => DPS
[1] => Support))
[Char2] => Array
([id] => 2
[name] =>Char2
[title] =>Example
[tags] => Array
([0] => Tank
[1] => N/A)
)
)
etc...
$arr2=
Array
([games] => Array
([gameId] => 123
[gameType => Match
[char_id] => 1
[stats] => Array
([damage] => 55555
[kills] => 5)
)
([gameId] => 157
[gameType => Match
[char_id] => 2
[stats] => Array
([damage] => 12642
[kills] => 9)
)
etc...
Basically, I need almost all the data in $arr2... but only the Char name from $arr1. How could I merge or add the $arr1['name'] key=>value into $arr2 where $arr1['id'] is equal to $arr2['char_id'] as the "id" field of each array is the same number.
I've attempted using array_merge and array_replace, but I haven't come up with any working solutions. This is also all data that I am receiving from a 3rd party, so I have no control on initial array setup.
Thanks for any help or suggestions!
Actually, this is quite straighforward. (I don't think there a built-in function that does this.)
Loop $arr2 and under it loop also $arr1. While under loop, just add a condition that if both ID's match, add that particular name to $arr2. (And use some referencing & on $arr2)
Consider this example:
// your data
$arr1 = array(
'type' => 'characters',
'version' => '5.6.7.8',
'data' => array(
'Char1' => array(
'id' => 1,
'name' => 'Char1',
'title' => 'Example',
'tags' => array('DPS', 'Support'),
),
'Char2' => array(
'id' => 2,
'name' => 'Char2',
'title' => 'Example',
'tags' => array('Tank', 'N/A'),
),
),
);
$arr2 = array(
'games' => array(
array(
'gameId' => 123,
'gameType' => 'Match',
'char_id' => 1,
'stats' => array('damage' => 55555, 'kills' => 5),
),
array(
'gameId' => 157,
'gameType' => 'Match',
'char_id' => 2,
'stats' => array('damage' => 12642, 'kills' => 9),
),
),
);
foreach($arr2['games'] as &$value) {
$arr2_char_id = $value['char_id'];
// loop and check against the $arr1
foreach($arr1['data'] as $element) {
if($arr2_char_id == $element['id']) {
$value['name'] = $element['name'];
}
}
}
echo '<pre>';
print_r($arr2);
$arr2 should look now like this:
Array
(
[games] => Array
(
[0] => Array
(
[gameId] => 123
[gameType] => Match
[char_id] => 1
[stats] => Array
(
[damage] => 55555
[kills] => 5
)
[name] => Char1 // <-- name
)
[1] => Array
(
[gameId] => 157
[gameType] => Match
[char_id] => 2
[stats] => Array
(
[damage] => 12642
[kills] => 9
)
[name] => Char2 // <-- name
)
)
)
Iterate over $arr2 and add the data to it from the matching $arr1 array value:
$i = 0;
foreach($arr2['games'] as $arr2Game){
$id = $arr2Game['char_id'];
$arr2['games'][$i]['name'] = $arr1['data'][$id]['name'];
$i++;
}
Have not tested this code.
If I'm understanding you correctly, you want to add a name index to each of the arrays within the $arr2['games'] array.
foreach($arr2['games'] as $key => $innerArray)
{
$arr2['games'][$key]['name'] = $arr1['data']['Char'.$innerArray['char_id']]['name'];
}

count value occurance and group by date

I get this date from datebase
Array
(
[0] => Array
(
[page] => login
[timestamp] => 2013-11-06 12:06:30
)
[1] => Array
[page] => changepage
[timestamp] => 2013-11-06 12:06:31
)
and so on..
I want to count the entries from the same day to make
Array
(
[0] => Array
(
[timestamp] => 2013-11-06 // only by the same day..
[count] => 4
)
)
or even
Array
(
[0] => Array
(
[timestamp] => 2013-11-06
[login] => 2
[changepage] => 4
)
)
I've tried
function format($data)
{
$dates = array();
for ($i = 0; $i < count($data); $i++)
{
if ($data[$i]['page'] == 'login')
{
if (!isset($dates[explode(' ', $data[$i]['timestamp'])[0]]))
array_push($dates, array('date' => explode(' ', $data[$i]['timestamp'])[0], 'login' => 1));
else
{
foreach ($dates as $date) {
if ($date['date'] == explode(' ', $data[$i]['timestamp'])[0])
$date['login'] += 1;
}
}
}
return $dates;
}
but that gives me only one record of
Array( Array ( 'timestamp' => '2013-11-06', 'login' => 1) )
In conclosion I want to sum the entries with the same day and same page
(My best solution would be getting 2 arrays one with sum of all the pages and one with detailed page sum)
Here's the solution to your question:
function format($data) {
$result = array();
foreach ($data as $item) {
$date = substr($item['timestamp'], 0, 10);
#$result[$date]['timestamp'] = $date;
#$result[$date][$item['page']]++;
}
sort($result);
return $result;
}
For each item in the array, it first truncates the time part of the timestamp field using substr. Use the date value as the key of the result array, add a timestamp field using this same date value, and increase the value of the other fields (containing page names). I use # operator here to prevent the Notice error when the key (index) doesn't exist yet.
After all items have been processed, sort the result array to change the keys into numeric indices and it becomes a regular array.
Here's the test I run:
$data = array(
array(
'page' => 'login',
'timestamp' => '2013-11-06 12:06:30'
),
array(
'page' => 'changepage',
'timestamp' => '2013-11-06 12:06:45'
),
array(
'page' => 'login',
'timestamp' => '2013-11-06 13:06:30'
),
array(
'page' => 'changepage',
'timestamp' => '2013-11-06 14:06:45'
),
array(
'page' => 'changepage',
'timestamp' => '2013-11-06 14:06:50'
),
array(
'page' => 'login',
'timestamp' => '2013-11-07 12:06:30'
),
array(
'page' => 'changepage',
'timestamp' => '2013-11-07 12:06:45'
)
);
print_r(format($data));
Anda the output is:
Array
(
[0] => Array
(
[timestamp] => 2013-11-06
[login] => 2
[changepage] => 3
)
[1] => Array
(
[timestamp] => 2013-11-07
[login] => 1
[changepage] => 1
)
)
There, hope it helps!

Complex & Confusing PHP Array Calculations

I have set of data that I need help with. I need to make a difficult calculation and array sort through several multidimensional arrays and the logic and syntax is giving me a headache.
Basically what I need it:
an array of keywords
I need to query a database and store some results for each keyword. (ID and Count of keyword matches)
I need to then flip the array around so instead of keywords being the parent element, it's IDs with the count of matches for each keyword within
I need to perform a calculation to get a single number from these number of matches
I need to sort the array so I can see which ID yielded the highest match value in the database, so I can query and output the relevant data.
I know how I am going to do the calculation for the relevancy now, it's just I've only briefly worked with single dimension arrays and I don't know how to syntactically represent what I need with this example. Could anyone give me a hand?
Here is a sample of what I want - not sure if this is syntactically the best way to show you, but hopefully you'll get the picture:
Array
(
[Keywords] => Array
(
["wax"] => Array
(
[ID] => 1
[Match] => 8
[ID] => 2
[Match] => 10
)
["hard"] => Array
(
[ID] => 1
[Match] => 2
[ID] => 2
[Match] => 37
)
)
Then this array would need to be translated to:
Array
(
[ID] => Array
(
["1"] => Array
(
[Keyword] => "wax"
[Match] => 8
[Keyword] => "hard"
[Match] => 10
)
["2"] => Array
(
[Keyword] => "wax"
[Match] => 2
[Keyword] => "hard"
[Match] => 37
)
)
This code:
$arr = array
(
"wax" => array
(
array(
'ID' => 11,
'Match' => 8
),
array(
'ID' => 21,
'Match' => 10
)
),
"hard" => array
(
array(
'ID' => 11,
'Match' => 2
),
array(
'ID' => 21,
'Match' => 37
)
)
);
$byid = array();
foreach($arr as $kw => $res) {
foreach($res as $r) {
$byid[$r['ID']][] = array('Keyword' => $kw, 'Match' => $r['Match']);
}
}
var_export($byid);
gives:
array (
11 =>
array (
0 =>
array (
'Keyword' => 'wax',
'Match' => 8,
),
1 =>
array (
'Keyword' => 'hard',
'Match' => 2,
),
),
21 =>
array (
0 =>
array (
'Keyword' => 'wax',
'Match' => 10,
),
1 =>
array (
'Keyword' => 'hard',
'Match' => 37,
),
),
)
I hope it helps.
You can query the db and create both the arrays by,
$query = "select id, keyword, count(*) as keyword_count from [your table] group by keyword";
$result = mysql_query($query);
while($row = mysql_fetch_array($result)){
$keyword = $row['keyword'];
$id = $row['id'];
$count = $row['keyword_count'];
$first_array["keywords"]["$keyword"] = array('id' => $id, 'match' => $count);
$second_array["id"]["$id"] = array('keyword' => $keyword, 'match' => $count);
}
print_r($first_array);
print_r($second_array);

Categories