How to get the difference between two arrays of objects - php

I have 2 array of objects, for example
$arr1 = [
(new MyClass())->setId(1),
(new MyClass())->setId(2),
(new MyClass())->setId(3),
];
$arr2 = [
(new MyClass())->setId(1),
(new MyClass())->setId(2),
];
I'd need to find the difference between these 2 arrays, in this example I'd need to get an array with a single element, the one with id == 3.
I know I should use array_udiff (maybe) but I couldn't figure out how.

The following logic might help:
<?php
class MyClass
{
public $id = null;
public function setId($id) {
$this->id = $id;
return $this;
}
}
$arr1 = [
(new MyClass())->setId(1),
(new MyClass())->setId(2),
(new MyClass())->setId(3),
];
$arr2 = [
(new MyClass())->setId(1),
(new MyClass())->setId(2),
];
$difference = array_udiff($arr1, $arr2,
function ($objOne, $objTwo) {
return $objOne->id - $objTwo->id;
}
);
Output:
Array
(
[2] => MyClass Object
(
[id] => 3
)
)
working demo

Related

Recursive function return issue

I'm writing a recursive function like below:
private function getManager($employee)
{
$manager = $employee->manager;
if ($manager) {
array_push($this->managers, $manager->id);
$this->getManager($manager);
}
return;
}
This function receive an employee and find his manage. If find a manage, then push manager id into an array ($this->managers on line 5). Then call this function recursively and pass manager as an employee. If no manager found on line 3, then this function just return (line 8).
So my question is, is their any problem if i'm not return the recursive call at line 6 ($this->getManager($manager);)
Not sure if this is what you think, but it works.
function getManagers($employee)
{
$managers = [];
if (isset($employee->manager)) {
array_push($managers, $employee->manager->id);
array_push($managers, ...getManagers($employee->manager));
}
return $managers;
}
No, there is absolutely no benefit in writing the empty return. The method will halt regardless of the existence of the return.
Please observe the two methods below which show identical, error-less outcomes regardless of the return.
Code: (Demo)
class Management
{
private $managers = [];
function __construct($managerTree)
{
$this->getManager($managerTree);
var_export($this->managers);
echo "\n---\n";
$this->managers = [];
var_export($this->managers);
echo "\n---\n";
$this->getManager2($managerTree);
var_export($this->managers);
}
private function getManager(?object $employee): void
{
$manager = $employee->manager;
if ($manager) {
array_push($this->managers, $manager->id);
$this->getManager($manager);
}
return;
}
private function getManager2(?object $employee): void
{
$manager = $employee->manager;
if ($manager) {
array_push($this->managers, $manager->id);
$this->getManager($manager);
}
}
}
new Management(
(object) [
'id' => 3,
'manager' => (object) [
'id' => 2,
'manager' => (object) [
'id' => 1,
'manager' => null
]
]
]
);
Output:
array (
0 => 2,
1 => 1,
)
---
array (
)
---
array (
0 => 2,
1 => 1,
)

How to convert array to multidimensional array with special keys using php?

I have an array
$array = [
0=>1
1=>Jon
2=>jon#email.com
3=>2
4=>Doe
5=>doe#email.com
6=>3
7=>Foo
8=>foo#email.com
]
What I`d like to do is to add and extra value to each value.
Something like this so I can access it when looping through the array
$array=[
0=>1[id]
1=>Jon[name]
2=>jon#email.com[email]
3=>2[id]
4=>Doe[name]
5=>doe#email.com[email]
6=>3[id]
7=>Foo[name]
8=>foo#email.com[email]
]
I guess it would be a multidimensional array?
What would be the proper way of doing it?
Loop through array and check key of items and based of it create new array and insert values in it.
$newArr = [];
foreach($array as $key=>$value){
if ($key % 3 == 0)
$newArr[] = ["id" => $value];
if ($key % 3 == 1)
$newArr[sizeof($newArr)-1]["name"] = $value;
if ($key % 3 == 2)
$newArr[sizeof($newArr)-1]["email"] = $value;
}
Check result in demo
yes just use 2 dimension array
$arr = array();
$arr[0][0] = "1"
$arr[0][1] = "Jon"
$arr[0][2] = "jon#email.com"
$arr[1][0] = "2"
$arr[1][1] = "Doe"
$arr[1][2] = "doe#email.com"
Since an array is a map in PHP, I'd recommend to use it like a map or to create a class holding the data.
$arr = array();
$arr[0]['ID'] = 1;
$arr[0]['name'] = "John";
$arr[0]['mail'] = "john#email.com;
Example for one class:
<?PHP
class User
{
public $id;
public $name;
public $mail;
function __construct($ID,$name,$mail)
{
$this->id = $ID;
$this->name = $name;
$this->mail = $mail;
}
}
?>
and then you can simply use it like that:
<?PHP
require_once("User.php");
$user = new User(1,"Mario","maio290#foo.bar");
echo $user->name;
?>
A simple, yet often-used solution is to use multidimensional array with string keys for better readability:
$array = [
0 => [
'id' => 1,
'name' => 'Jon',
'email' => 'jon#email.com',
],
1 => [
'id' => 2,
'name' => 'Doe',
'email' => 'doe#email.com',
],
2 => [
'id' => 3,
'name' => 'Foo',
'email' => 'foo#email.com',
],
];
You can loop through this like so:
for ($array as $item) {
// $item['id']
// $item['name']
// $item['email']
}
But since PHP is an object-oriented language, I'd suggest creating a class for the data-structure. This is even easier to read and you can very easily add functionality related to the entity etc.
class Person {
public $id;
public $name;
public $email;
function __construct($id, $name, $email) {
$this->id = $id;
$this->name = $name;
$this->email = $email;
}
}
$array = [
0 => new Person(1, 'Jon', 'jon#email.com'),
1 => new Person(2, 'Doe', 'doe#email.com'),
2 => new Person(3, 'Foo', 'foo#email.com'),
];
You can loop through this like so:
for ($array as $person) {
// $person->id
// $person->name
// $person->email
}
Use array_map on the result of array_chunck this way:
$array=array_map(function($val){ return array_combine(['id','name','email'],$val);}, array_chunk($array,3));
note that the second parameter of array_chunk depend of the number of columns and the first array used in array_combine too
see the working code here
You can also do like this:
$array1 = ["name"=>"alaex","class"=>4];
$array2 = ["name"=>"aley","class"=>10];
$array3 = ["student"=>$array1,"student2"=>$array2];
print_r($array3);

Flatten a Nested JSON Array in PHP

I need to flatten a nested JSON Array in PHP, the list I have is:
["Paris", "Barcelona", ["Glasgow", ["Sydney"]]]],"Budapest"]
So far I have this code:
<?php
$array = [
'city' => [
'Paris',
'Berlin',
'London',
],
];
$flattened = iterator_to_array(new RecursiveIteratorIterator(
new RecursiveArrayIterator($array)
), false);
print_r($flattened);
I needs to use this
print_r((new Flattener($jsonArray))→flatten());
This command should return a single-dimensional PHP array.
Any ideas of what I am missing?
You need to
create a class with a constructor (__construct) that takes the array and
create a flatten method which takes the array and flattens it.
An example you could use:
class Flattener {
private $array;
public function __construct($array) {
$this->array = $array;
}
public function flatten() {
return iterator_to_array(new RecursiveIteratorIterator(
new RecursiveArrayIterator($this->array)), false);
}
}
print_r((new Flattener($array))->flatten());

How to convert array to object

First, I have tried to find solution within the source here but couldn't find what I am looking so posting as a new question. Thanks for your help
I want to convert Array to Object. Here is what I am getting output
Array
(
[0] => stdClass Object
(
[id] => 1
[username] => robustsolver
[first_name] => John
[last_name] => Smith
)
[1] => stdClass Object
(
[id] => 2
[username] => pickypacker
[first_name] => Peter
[last_name] => Packer
)
)
So if I want any column for all users than I have to write code $users[0]->first_name; which gives me only one item. But what I am looking is to use $users->first_name and this should return an array of all user's column (here is first_name)
Hope I have explain in better way. :S
You can try this where $arr is your array:
function filter_callback($element) {
return $element->first_name;
}
$result= array_map('filter_callback', $arr);
From a quick test, this seems to work. It keeps objects of the array without your wanted property but its value is set to NULL. Not sure if that's what you want but you can edit the filter_callback to remove such elements.
Maybe something like this will work (not tested):
$arr = array(...); // array of objects (in)
$obj = new Object; // object of arrays (out)
foreach($arr as $a) {
foreach(get_object_vars($a) as $k=>$v) {
if(!property_exists($obj, $k)) {
$obj->{$k} = array();
}
$obj->{$k}[] = $v;
}
}
consider defining a new class:
class User_objects
{
public $first_name;
public $username;
public $last_name;
public function __construct()
{
$this->first_name = array();
$this->username = array();
$this->last_name = array();
}
}
then:
consider $array_of_objects to be your array of objects (input).
$users = new User_objects();
foreach ($array_of_objects as $object)
{
$users->first_name[] = $object->first_name; // append to array
$users->last_name[] = $object->last_name;
$users->username[] = $object->username;
}
then you can get your array from $users->first_name
You can write a simple helper function that will aid in the columns you wish to select:
function prop_selector($prop)
{
return function($item) use ($prop) {
return $item->{$prop};
};
}
$first_names = array_map(prop_selector('first_name'), $users);
$last_names = array_map(prop_selector('last_name'), $users);

The result of array_unique

Working with DateTime in projects again have a problem with duplicating if use array_unique to array which have a elemts of object,(but probles only with DateTime), see code:
class simpleClass
{
public $dt;
function __construct($dt)
{
$this->dt = $dt;
}
}
$dateObj = new simpleClass(new DateTime);
$std = new stdClass;
$arr = [$dateObj, $dateObj, $std, $std, $std, $std];
var_dump(array_unique($arr, SORT_REGULAR));
Expected 1 element with dateObj
But actually there 2
Function array_unique() will compare strings, so objects will be casted to strings. Solution to that would be to use __toString() magic method to return full date identifier:
class simpleClass
{
public $dt;
function __construct(DateTime $dt) {
$this->dt = $dt;
}
public function __toString() {
return $this->dt->format('r');
}
}
$dateObj1 = new simpleClass(new DateTime);
$dateObj2 = new simpleClass(new DateTime);
$dateObj3 = new simpleClass(new DateTime('today'));
$arr = [$dateObj1, $dateObj2, $dateObj3];
print_r(array_unique($arr));
Demo.
I still can't understand. Setting the array with:
$arr = [$dateObj, $dateObj, $std, $std];
returns:
array (size=2)
0 =>
object(simpleClass)[1]
public 'dt' =>
object(DateTime)[2]
public 'date' => string '2013-11-14 14:37:08' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/Rome' (length=11)
2 =>
object(stdClass)[3]
This way, array_unique seems to work...

Categories