How to combine objects to array without removing duplicates in PHP - php

I have 3 objects and I want them to combine into 1 array. There are duplicate property names in objects, but I want them too (with renames property name). How can I do that?
$object1 = {
"id": "10",
"unit_number": "12565"
},
$object2 = {
"id": "20",
"full_name": "Lorem Ipsm"
},
$object3 = {
"id": "30",
"phone": "123456789"
}
I want the output like,
array = (
"id1" => "10",
"unit_number" => "12565",
"id2" => "20",
"full_name" => "Lorem Ipsm",
"id3" => "30",
"phone" => "123456789"
);
I have tried to assign them to one array like,
$arr = array();
$arr['obj1'] = $object1;
$arr['obj2'] = $object2;
$arr['obj3'] = $object3;
Now I thought of doing a foreach, but I am stuck. My actual object is too big. So there are many duplicates. Not just this one.

I think you can achieve this using below code,
$object1 = (object) ['id' => '10', "unit_number"=> "12565", "name" => 'Test name'];
$object2 = (object) ['id' => '20', "full_name"=> "Lorem Ipsm"];
$object3 = (object) ['id' => '30', "phone"=> "123456789", "name" => "test name 1"];
$array1 = (array) $object1;
$array2 = (array) $object2;
$array3 = (array) $object3;
function array_merge_dup_keys() {
$arrays = func_get_args();
$data = array();
foreach ($arrays as $a) {
foreach ($a as $k => $v) {
$key1 = check_key_exists($k,$data);
$data[$key1] = $v;
}
}
return $data;
}
function check_key_exists($key,$array,$loop_count=1)
{
if(array_key_exists ( $key , $array ))
{
$val = explode('_',$key);
$count = isset($val[1]) ? $val[1] : $loop_count;
$start_key = isset($val[0]) ? $val[0] : $key;
$key = $start_key.'_'.$loop_count;
$key = check_key_exists($key,$array,$count+1);
}
return $key;
}
$data = array_merge_dup_keys($array1 ,$array2,$array3);
The output ($data) of above code will be,
Array
(
[id] => 10
[unit_number] => 12565
[name] => Test name
[id_1] => 20
[full_name] => Lorem Ipsm
[id_2] => 30
[phone] => 123456789
[name_1] => test name 1
)

Maybe something like this? (untested, possible typos/syntax errors...)
// this looks like json, not PHP
// "object1": {
// "id": "10",
// "unit_number": "12565"
// },
// "object2": {
// "id": "20",
// "full_name": "Lorem Ipsm"
// },
// "object3": {
// "id": "30",
// "phone": "123456789"
// }
// here is a php array for that data
$objArray = array(
"object1" => array( "id"=>"10", "unit_number"=>"12565"),
"object2" => array( "id"=>"20", "full_name"=>"Lorem Ipsm"),
"object3" => array( "id"=>"30", "phone"=>"123456789")
);
$newArray = array();
foreach( $objArray as $key=>$value)
{
// the the id "append"
$idAppend = substr($key, strlen("object"));
foreach($value as $subkey=>$subvalue)
{
$newkey = $subkey;
if ( strcmp($subkey, "id") == 0 ) // it is the id string
{
$newkey = $subkey.$idAppend;
}
$newArray[$newkey] = $subvalue;
}
}

Related

array_filter function in function

I have this function, where a array_filter function is included:
$var = "test";
function mainFunction() {
global $var;
$myNewArray = array();
$data = array("a", "b", "c");
array_filter($data, function ($value) {
global $myNewArray;
$myNewArray[] = $value;
});
print_r($myNewArray); // TEST OUTPUT
}
mainFunction();
Problem:
My test output myNewArray is empty.
I know that my array_filter function is senless at the moment until I check no values.
But only for testing, I would like to use it, to create a newArray. But this doesn't work. Where is my mistake?
UPDATE
I updated my code:
function mainFunction() {
global $var;
$myNewArray = array();
$data[] = array("id" => "1", "content" => "Hello");
$data[] = array("id" => "2", "content" => "World");
$myNewArray = array_filter($data, function ($value) {
if ($value['content'] == "World") {
return $value['content'];
}
});
print_r($myNewArray); // TEST OUTPUT
}
mainFunction();
This works, but not correctly.
I would like to save only the content value.
But my $myNewArray looks like this:
Array
(
[0] => Array
(
[id] => 2
[content] => World
)
)
Instead of
Array
(
[0] => Array
(
[content] => World
)
)
I would combine array_filter and array_map for this.
$data[] = array("id" => "1", "content" => "Hello");
$data[] = array("id" => "2", "content" => "World");
// filter the data
$data = array_filter($data, fn ($value) => $value['content'] === 'World');
// map the data
$data = array_map(fn ($value) => ['content' => $value['content']], $data);
// reset indexes
$data = array_values($data);
print_r($data);
Example: https://phpize.online/s/9U
Everything seems to work fine.
<?php
$data = [];
$data[] = array("id" => "1", "content" => "Hello");
$data[] = array("id" => "2", "content" => "World");
$filtered_data = array_filter($data, function($value) {
return $value['content'] == "World";
});
print_r($filtered_data);
The output is just like expected:
Array (
[1] => Array
(
[id] => 2
[content] => World
)
)
But if you want to leave only some fields in resulting array, array_filter will not help you (at least without a crutch).
You may want to iterate source array and filter it by yourself.
<?php
$data = [];
$data[] = array("id" => "1", "content" => "Hello");
$data[] = array("id" => "2", "content" => "World");
$filtered_data = [];
foreach($data as $v) {
if($v['content'] == "World")
$filtered_data[] = ["content" => $v['content']];
}
print_r($filtered_data);
The output then would be:
Array (
[0] => Array
(
[content] => World
)
)
You want two different things :
filter your array (keep only some elements)
map your array (change the value of each element)
Filter your array
On your second attempt you've done it right but array_filter callback function expect a boolean as the return value. It will determine wherever array_filter need to keep the value or not.
Map your array
You need to remove all value on each element except the "content" value. You can use array_map to do that.
function mainFunction() {
$data[] = array("id" => "1", "content" => "Hello");
$data[] = array("id" => "2", "content" => "World");
$myNewArray = array_filter($data, function ($value) {
if ($value['content'] == 'World') {
return true;
}
return false;
});
// myNewArray contains now the willing elements, but still don't have the willing format
/* myNewArray is [
0 => [
'id' => '2',
'content' => 'World'
]
]*/
$myNewArray = array_map($myNewArray, function($value){
return [
'content' => $value['content']
];
});
// myNewArray contains now the willing elements with the willing format
/* myNewArray is [
0 => [
'content' => 'World'
]
] */
}
mainFunction();
In mainFunction you are not using $myNewArray as global so it's only in the scope, but in the array_filter function you are using global $myNewArray;
$var = "test";
$myNewArray; // global array
function mainFunction() {
global $var, $myNewArray;//if this is not present it's not global $myNewArray
$myNewArray = array();
$data = array("a", "b", "c");
array_filter($data, function ($value) {
global $myNewArray;//this uses global
$myNewArray[] = $value;
});
print_r($myNewArray); // TEST OUTPUT
}
mainFunction();
Here is an example of you code without global $myNewArray
$var = "test";
function mainFunction($var) {
$myNewArray = array();
$data = array("a", "b", "c");
$myNewArray[] = array_filter($data, function ($value) {
return $value;
});
print_r($myNewArray); // TEST OUTPUT
}
mainFunction($var);
Answer to Update:
You can use array_reduce to achieve that
function mainFunction() {
global $var;
$myNewArray = array();
$data[] = array("id" => "1", "content" => "Hello");
$data[] = array("id" => "2", "content" => "World");
$myNewArray = array_reduce($data, function($accumulator, $item) {
if ($item['content'] === "World")
$accumulator[] = ['content' => $item['content']];
return $accumulator;
});
print_r($myNewArray); // TEST OUTPUT
}
mainFunction();
you can use this code..........
<?php
function test_odd($var)
{
return($var & 1);
}
$a1=array(1,3,2,3,4);
print_r(array_filter($a1,"test_odd"));
?>

Specific problem with traversing an array in php

I have given the array:
array(
"firstName": null,
"lastName": null,
"category": [
"name": null,
"service": [
"foo" => [
"bar" => null
]
]
]
)
that needs to be transform into this:
array(
0 => "firstName",
1 => "lastName",
2 => "category",
"category" => [
0 => "name",
1 => "service",
"service" => [
0 => "foo",
"foo" => [
0 => "bar"
]
]
]
)
The loop should check if a value is an array and if so, it should add the key as a value (0 => category) to the root of array and then leave the key as it is (category => ...) and traverse the value again to build the tree as in example.
I am stuck with this and every time I try, I get wrong results. Is there someone who is array guru and knows how to simply do it?
The code so far:
private $array = [];
private function prepareFields(array $fields):array
{
foreach($fields as $key => $value)
{
if(is_array($value))
{
$this->array[] = $key;
$this->array[$key] = $this->prepareFields($value);
}
else
{
$this->array[] = $key;
}
}
return $this->array;
}
You could make use of array_reduce:
function prepareFields(array $array): array
{
return array_reduce(array_keys($array), function ($result, $key) use ($array) {
$result[] = $key;
if (is_array($array[$key])) {
$result[$key] = prepareFields($array[$key]);
}
return $result;
});
}
Demo: https://3v4l.org/3BfKD
You can do it with this, check the Demo
function array_format(&$array){
$temp_array = [];
foreach($array as $k=>$v){
$temp_array[] = $k;
if(is_array($v)){
array_format($v);
$temp_array[$k] = $v;
}
}
$array = $temp_array;
}
array_format($array);
print_r($array);

Merge multi-dimensional arrays and sum column values which share a common value in another column

I have 3 arrays for storing posts,comments, and likes.
These are the JSON strings:
//comments JSON (stores user and comment points)
$comments='[
{
"user": "5",
"points": "12"
},
{
"user": "2",
"points": "1"
},
{
"user": "3",
"points": "1"
}
]';
//likes(stores user and likes point)
$likes='[
{
"user": "1",
"points": 7
},
{
"user": "4",
"points": 4
},
{
"user": "3",
"points": 1
}
]';
//posts (stores user and post points)
$posts='[
{
"user": "1",
"points": "6"
},
{
"user": "3",
"points": "2"
},
{
"user": "2",
"points": "1"
}
]';
I convert these JSONs into arrays like this:
$comment_array = json_decode($comments,TRUE);
$like_array = json_decode($likes,TRUE);
$post_array = json_decode($posts,TRUE);
//echo '<pre>';
//print_r($comment_array);
//print_r($like_array);
//print_r($post_array);
//echo '</pre>';
Now, I'm trying to sum these points and save the result in a new array. It's not mandatory that a user should have entries in all the three arrays. It depends on whether a user has made a comment, post or like.
function mergeArrays($filenames, $titles, $descriptions) {
$result = array();
foreach ( $filenames as $key=>$name ) {
$result[] = array( 'filename' => $name, 'title' => $titles[$key], 'descriptions' => $descriptions[ $key ] );
}
return $result;
}
The above function can merge all the three arrays.
$merged= mergeArrays($comment_array, $like_array, $post_array);
echo '<pre>';
print_r($merged);
echo '</pre>';
However, each array after merging is stored as an index element.
How can I get a result something like this:
$result='[
{
"user": "1",
"points": "13"
},
{
"user": "2",
"points": "2"
},
{
"user": "3",
"points": "4"
},
{
"user": "4",
"points": "4"
},
{
"user": "5",
"points": "12"
}
]';
Considering your three arrays, this code will get you an array with: points, votes and diferent users.
Edit: Adding additional array and printing it to get the output desired by question.
$points = 0;
$uniqueUsers = array();
$votes = 0;
$users = 0;
$result = array();
//Comments
if (!empty($comment_array)) {
foreach ($comment_array as $item) {
if (!in_array($item['user'], $uniqueUsers)) {
array_push($uniqueUsers, $item['user']);
$result[$item['user']] = 0;
}
$votes ++;
$result[$item['user']] += $item['points'];
}
}
// Likes
if (!empty($like_array)) {
foreach ($like_array as $item) {
if (!in_array($item['user'], $uniqueUsers)) {
array_push($uniqueUsers, $item['user']);
$result[$item['user']] = 0;
}
$votes ++;
$result[$item['user']] += $item['points'];
}
}
// Posts
if (!empty($post_array)) {
foreach ($post_array as $item) {
if (!in_array($item['user'], $uniqueUsers)) {
array_push($uniqueUsers, $item['user']);
$result[$item['user']] = 0;
}
$votes ++;
$result[$item['user']] += $item['points'];
}
}
foreach ($result as $idUser=>$points) {
echo "\n";
echo "\n" . 'User: ' . $idUser;
echo "\n" . 'Points: ' . $points;
}
$results = array('users'=> count($uniqueUsers), 'votes'=>$votes, 'points'=> $points);
//print_r($results);
The solution using array_column, array_walk_recursive and array_values functions:
...
$comments = array_column($comment_array, 'points', 'user');
$likes = array_column($like_array, 'points', 'user');
$posts = array_column($post_array, 'points', 'user');
$list = [$comments, $likes, $posts];
$result = [];
array_walk_recursive($list, function($v, $k) use(&$result){
if (key_exists($k, $result)){
$result[$k]['points'] += $v;
} else {
$result[$k] = ['user' => $k, 'points' => $v];
}
});
$result = array_values($result);
print_r($result);
The output:
Array
(
[0] => Array
(
[user] => 5
[points] => 12
)
[1] => Array
(
[user] => 2
[points] => 2
)
[2] => Array
(
[user] => 3
[points] => 4
)
[3] => Array
(
[user] => 1
[points] => 13
)
[4] => Array
(
[user] => 4
[points] => 4
)
)
Do the following to get one array with summed points:
$collections = array(
'comments' => json_decode($comments,TRUE),
'likes' => json_decode($likes,TRUE);,
'posts' => json_decode($posts,TRUE),
);
$newArray = array();
foreach ($collections as $collection) {
foreach ($collection as $user) {
$newArray[$user->user] += $user->points;
}
}
There are two important points to make if you want to learn the "best" way to handle these types of operations.
Don't use iterated in_array() calls when isset() can be used instead. This is because isset() is much more efficient than in_array().
Use temporary keys to identify duplicate occurrences, then re-index your results when finished -- usually with array_values(), but this time I used array_multisort() to re-order the results AND re-index.
Code: (Demo)
$merged = array_merge(json_decode($comments, true), json_decode($likes, true), json_decode($posts, true));
$result = [];
foreach ($merged as $entry) {
if (!isset($result[$entry['user']])) {
$result[$entry['user']] = $entry;
} else {
$result[$entry['user']]['points'] += $entry['points'];
}
}
array_multisort(array_column($result, 'user'), $result);
// usort($result, function($a, $b) { return $a['user'] <=> $b['user']; });
// array_multisort() will outperform `usort()` in this case.
echo json_encode($result);
Output:
[{"user":"1","points":13},{"user":"2","points":2},{"user":"3","points":4},{"user":"4","points":4},{"user":"5","points":"12"}]
Decode each array and merge them together into a multi-dimensional array.
Iterate each subarray and determine if it is the first occurrence of the user. If so, retain the entire subarray. If not, only increase the points tally within that subarray.
When the loop is finished, sort by user ascending.
This is clean, direct, and readable.

Build array of keys and values?

Im trying to build a json array in php with this structure:
[{"id":"name last name",
"id":"name last name",
"id":"name last name"
}]
where the id key is always a different number, not only id string
Im trying to do this:
for ($i = 0; $i < count($array); $i++){
//$namesArray[] = array($array[$i]["id"] =>$array[$i]["name"].
// " ".$array[$i]["last"]." ".$array[$i]["name"]);
$namesArray[] = array_fill_keys(
$array[$i]["id"],
$array[$i]["name"]." ".
$array[$i]["last"]." ".
$array[$i]["name"]
);
}
echo json_encode($namesArray);
With the commented lines I get something like this:
[{"id":"name last name"},
{"id":"name last name"}
]
But I dont want that, I want all keys and values in a single array.
Thanks.
Keep your code clean
$array = [];
$array[] = ['id'=>3 , 'name'=>'H', 'last'=>'bensiali' ];
$array[] = ['id'=>4 , 'name'=>'Simon', 'last'=>'Says' ];
$array[] = ['id'=>5 , 'name'=>'Mohammed', 'last'=>'Ali' ];
$val = [];
foreach ($array as $key => $value) {
$val[$value['id']] = sprintf("%s %s" , $value['name'] , $value['last']);
}
echo json_encode($val);
And output will be:
{"3":"H bensiali","4":"Simon Says","5":"Mohammed Ali"}
Here is how you can do it:
// sample data
$array = array(
array("id" => 1, "name" => "James", "last" => "Last"),
array("id" => 2, "name" => "Micheal", "last" => "Jackson"),
);
// create empty object (associative array)
$obj = (object) array();
// add key/value pairs to that object
foreach ($array as $row) {
$obj->$row["id"] = $row["name"] . " " . $row["last"];
}
// wrap object in a single-element array
$result = array($obj);
// output to JSON string
echo json_encode($result, JSON_PRETTY_PRINT);
Output:
[
{
"1": "James Last",
"2": "Micheal Jackson"
}
]
You can use functional approach to fill desired array with array_reduce:
$array = [
['id' => 1, 'name' => 'name1', 'last' => 'last1'],
['id' => 2, 'name' => 'name2', 'last' => 'last2'],
['id' => 3, 'name' => 'name3', 'last' => 'last3'],
];
$newArray = array_reduce($array, function($carry, $item) {
$carry[$item['id']] = $item["name"]." ".
$item["last"]." ".
$item["name"];
return $carry;
});
var_dump($newArray);
And output will be:
array(3) {
[1]=>
string(17) "name1 last1 name1"
[2]=>
string(17) "name2 last2 name2"
[3]=>
string(17) "name3 last3 name3"
}

Prepend key value to array - PHP

I have the below code in a for..loop is there a way I can add values to the beginning of the array?
$data = array();
$initial = strtotime('11:00:00');
for (; $initial < strtotime("23:00:59"); $initial = strtotime("+15 minutes", $initial)) {
if ($initial > strtotime("+45 minutes", time())) {
$row['value'] = date('Hi', $initial);
$row['label'] = date('H:i', $initial);
$data['data'][] = $row;
}
}
I want to add the below values to the top of the array. I have tried using array_unshift but I don't think it supports key-value pairs.
if(!isBetween('22:00', '09:59', date('H:i'))) {
$row['value'] = "asap";
$row['label'] = "ASAP";
}
My array output
{
"data": [
{
"value": "1145",
"label": "11:45"
}
]
}
I want to get this
{
"data": [
{
"value": "asap",
"label": "ASAP"
},{
"value": "1145",
"label": "11:45"
},
]
}
Un-shift should work if you pass the arguments correctly:
array_unshift($data["data"], $prepend);
Alternatively, you could use array_merge, like this:
$data["data"] = array_merge(array($prepend), $data["data"]);
With the following example data:
$data = [
"data" => [
[
"value" => "1145",
"label" => "11:45"
]
]
];
$prepend = [
"value" => "asap",
"label" => "ASAP"
];
$data["data"] = array_merge(array($prepend), $data["data"]);
print_r($data);
You would get this output (with both solutions):
Array (
[data] => Array (
[0] => Array (
[value] => asap
[label] => ASAP
)
[1] => Array (
[value] => 1145
[label] => 11:45
)
)
)
If you need to prepend something to the array without the keys being reindexed and/or need to prepend a key value pair, you can use this short function:
function array_unshift_assoc(&$arr, $key, $val) {
$arr = array_reverse($arr, true);
$arr[$key] = $val;
return array_reverse($arr, true);
}
Source: http://php.net/manual/en/function.array-unshift.php

Categories