How to check duplicates in array of objects by first key? - php

I have an array of objects
[new BalanceSheet('2018', '356743', '-56913', '189632', '122733'),
new BalanceSheet('2018', '4562343', '236913', '198732', '6552733'),
new BalanceSheet('2017', '2234643', '55913', '19435342', '855342733')
]
And i need to throw an exception when the first key in object are duplicate another -> 2018 === 2018
I understand how i can to get the key
class BalanceSheet {
public function __construct(string $year, ...) {
$this->year = $year;
...
}
public function getYear() {
return $this->year;
}
private function isDuplicateData($sheets) {
foreach ($sheets as $key => $sheet) {
echo $key . ' year = ' . $sheet->getYear();
}
}
but i don't understand what the easiest way to compare keys in isDuplicateData

If all you need to do is throw an exception, then maybe create an array of the keys and apply array_unique().
private function isDuplicateData($sheets) {
$keys = [];
foreach ($sheets as $key => $sheet) {
$keys[]=$key;
}
if (count($keys) != count(array_unique($keys)){
//throw exception
}
}

How about using php array_filter:
$objects = array(
new BalanceSheet('2018', '356743', '-56913', '189632', '122733'),
new BalanceSheet('2018', '4562343', '236913', '198732', '6552733'),
new BalanceSheet('2017', '2234643', '55913', '19435342', '855342733'),
);
$known = array();
$filtered = array_filter($objects, function ($val) use (&$known) {
// In your case the key would be years
$unique = !in_array($val->years, $known);
$known[] = $val->years;
return $unique;
});

You can compare length of array and length of array_diff.
count($arrayA) == count(array_diff($arrayA,$arrayB));

If you want to delete duplicates you can use the PHP function array_unique, this will check for the duplicates and delete them:
array_unique ( $sheets );
If you want to throw an exception only, you can extract and add the years to another array then check if there are any duplicates:
private function isDuplicateData($sheets) {
$isdublicate = array();
foreach ($sheets as $key => $sheet) {
echo $key . ' year = ' . $sheet->getYear();
$isdublicate[] = $sheet->getYear();
}
for ($i = 0; $i < count($isdublicate); $i++)
{
if ($isdublicate[abs($isdublicate[$i])] >= 0)
$isdublicate[abs($isdublicate[$i])] = -$isdublicate[abs($isdublicate[$i])];
else
//Here throw the exception
}
}
The above for loop logic is here.

Related

PHP - How to dynamically input multi-dimensional arrays only knowing the keys?

I have a multi-dimensional array with key value pairs. Some of the values of the keys are arrays, and some of the values in that array are arrays as well. It is only 3 branches deep (for now), but I am trying to recursively loop through the array, save the key for each level of the branch, and create a new array when it reaches a string that also mimics the structure of the original array. When it reaches a string, there should be a new object instantiation for each value.
The code below sort of does this, but only creates a flat array.
foreach ($data as $key => $value) {
if (!is_array($value)) {
$a_objects[$key] = new Component([$key], $value);
} else {
foreach ($value as $valueKey => $valueValue) {
if (!is_array($valueValue)) {
$a_objects[$key . "_" . $valueKey] = new Component([$key, $valueKey], $valueValue);
} else {
foreach ($valueValue as $k => $v) {
$a_objects[$key . "_" . $valueKey . "_" . $k] = new Component([$key, $valueKey, $k], $v);
}
}
}
}
Here is my own best attempt at this but it does not seem to save into the b_objects after some testing it does not seem to be saving the object instances.
$b_objects = [];
function create_r($data, $id)
{
foreach ($data as $key => $value) {
if (is_array($value) == true) {
array_push($id, $key);
create_r($value, $id);
} else {
array_push($id, $key);
$b_objects[$key] = new Component($id, $value);
$id = [];
}
}
}
$id = [];
create_r($data, $id);
echo "this is b_objects";
echo "<pre>";
print_r($b_objects);
echo "</pre>";
I verified that $id array contains the right "keys". I feel like this solution is pretty close but I have no idea how to use my $id array to mimic the structure of the $data.
I want to be able to say $b_objects[$level1key][$level2key][$level3key]...[$leveln-1key] = new Component...
Thanks!
I suggest you pass $b_objects by reference to your create_r() function. Otherwise each function call will instantiate a new $b_objects variable which is not used anywhere in the code afterwards.
Passing by reference allows the function to actually change the input array. Notice the & sign in the function declaration.
function create_r($data, $id, &$res)
{
foreach ($data as $key => $value) {
if (is_array($value) == true) {
array_push($id, $key);
create_r($value, $id, $res);
} else {
array_push($id, $key);
$res[$key] = new Component($id, $value);
$id = [];
}
}
}
$id = [];
$b_objects = [];
create_r($data, $id, $b_objects);

return specific array form from function

i have this array
$array = [1, 2, 3, 4, 5];
and this function
function change($array) {
foreach ($array as $key => $value) {
$form[$key+5][$value-1] = $key-$value;
}
return $form;
}
change($array);
in it the form that i want to rearrange the array in is $form[$key+5][$value-1] = $key-$value; but i want to make it defined by a parameter like this
function change($array, $form) {
foreach ($array as $key => $value) {
$form;
}
return $form;
}
$x = change($array, $arr[$key+5][$value-1] = $key-$value);
$y = change($array, $arr[$key+5][$key+100] = $key+$value);
how can this be done?
Somebody will bash all of the evils of eval but if it is not user supplied (un-trusted) data, then this works:
function change($array, $form) {
foreach ($array as $key => $value) {
eval("\$result$form;");
}
return $result;
}
You need to call it with a string as shown:
$x = change($array, '[$key+5][$value-1] = $key-$value');
$y = change($array, '[$key+5][$key+100] = $key+$value');
This builds a string that looks like this: $result[$key+5][$key+100] = $key+$value; and evaluates it as PHP code.
It would be a lot more work, but you could pass in something to parse and adapt it to How to access and manipulate multi-dimensional array by key names / path?.

How to make first array value to uppercase

I am trying to make first array value to uppercase.
Code:
$data = $this->positions_model->array_from_post(array('position', 'label'));
$this->positions_model->save($data, $id);
So before save($data, $id) to database I want to convert position value to uppercase. I have tried by this
$data['position'] = strtoupper($data['position']);
but than it is not storing the value in db with uppercase but as it is what user inputs.
Current output of $data:
Array ( [position] => it [label] => Information Technology )
And I want it in uppercase as IT
Added Model Method
public function get_positions_array($id = NULL, $single = FALSE)
{
$this->db->get($this->_table_name);
$positions = parent::get($id, $single);
$array = array();
foreach($positions as $pos){
$array[] = get_object_vars($pos);
}
return $array;
}
Main MY_Model method
public function array_from_post($fields)
{
$data = array();
foreach ($fields as $field) {
$data[$field] = $this->input->post($field);
}
return $data;
}
This should work:
$data = $this->positions_model->array_from_post(array('position', 'label'));
$data['position'] = strtoupper($data['position']);
$this->positions_model->save($data, $id);
If Its not, then $data array have only read attribute.
The array_from_post() method returns an array with the format below:
$data = array(
'position' => 'it',
'label' => 'Information Technology'
);
So, you could make first value of the array to uppercase, by using array_map or array_walk functions as follows:
$data = array_map(function($a) {
static $i = 0;
if ($i === 0) { $i++; return strtoupper($a); }
else return $a;
}, $array);
Note: This only works on PHP 5.3+, for previous versions, use the function name instead.
Here is the array_walk example, which modifies the $data:
array_walk($data, function(&$value, $key) {
static $i = 0;
if ($i == 0) { $i++; $value = strtoupper($value); }
});
Again, if you're using PHP 5.2.x or lower, you could pass the function name instead.

how to skip the duplicate occurence of a row of data using ArrayObject in PHP?

am trying to print out only the unique values. since am receiving a huge object array from the I am trying to use now the ArrayObject class of PHP to iterate
$arrayobject = new ArrayObject($data);
$iterator = $arrayobject->getIterator();
while($iterator->valid()){
echo $iterator->current()->USERID. " : " .$iterator->current()->SUBCATID."<br/>";
$iterator->next();
}
here's the current result of that
201087 : 1
201146 : 1
201087 : 3
201087 : 2
as you can see, the first data has two other duplicates
and also, the first and second data has similar subcatid..
the objective is, print only the unique userid and subcatid..
how to skip those duplicate data, given that sample code of mine
as a starting point ?
Not quite sure I understand the question but maybe....
You can either sort the array and remember the current userid so your script can skip duplicates until it reaches another id.
<?php
$data = data();
usort(
$data,
function($a,$b) {
return strnatcmp($a->USERID, $b->USERID);
}
);
$current = null;
foreach( $data as $e ) {
if ( $current!=$e->USERID ) {
$current = $e->USERID;
echo $e->USERID, ' ', $e->SUBCATID, "\n";
}
}
function data() {
$x = array(
array(201087,1),
array(201146,1),
array(201087,3),
array(201087,2),
array(222222,3)
);
foreach($x as $y) {
$o = new StdClass;
$o->USERID = $y[0];
$o->SUBCATID = $y[1];
$data[] = $o;
}
return $data;
}
or the script remembers all previously processed ids, e.g. in a hashmap/array
<?php
$data = data();
$processed = array();
foreach( $data as $e ) {
if ( !isset($processed[$e->USERID]) ) {
$processed[$e->USERID] = true;
echo $e->USERID, ' ', $e->SUBCATID, "\n";
}
}
function data() {
$x = array(
array(201087,1),
array(201146,1),
array(201087,3),
array(201087,2),
array(222222,3)
);
foreach($x as $y) {
$o = new StdClass;
$o->USERID = $y[0];
$o->SUBCATID = $y[1];
$data[] = $o;
}
return $data;
}
both scripts print
201087 1
201146 1
222222 3
$ids = array(1,2,3,4,4);
$ids = array_unique($ids); // remove duplicates

Split an array into sub arrays

I would like to split an array:
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
based on the color attribute of each item, and fill corresponding sub arrays
$a = array("green", "yellow", "blue");
function isGreen($var){
return($var->color == "green");
}
$greens = array_filter($o, "isGreen");
$yellows = array_filter($o, "isYellow");
// and all possible categories in $a..
my $a has a length > 20, and could increase more, so I need a general way instead of writing functions by hand
There doesn't seem to exist a function array_split to generate all filtered arrays
or else I need a sort of lambda function maybe
You could do something like:
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$greens = array_filter($o, function($item) {
if ($item->color == 'green') {
return true;
}
return false;
});
Or if you want to create something really generic you could do something like the following:
function filterArray($array, $type, $value)
{
$result = array();
foreach($array as $item) {
if ($item->{$type} == $value) {
$result[] = $item;
}
}
return $result;
}
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$greens = filterArray($o, 'color', 'green');
$yellows = filterArray($o, 'color', 'yellow');
In my second example you could just pass the array and tell the function what to filter (e.g. color or some other future property) on based on what value.
Note that I have not done any error checking whether properties really exist
I would not go down the road of creating a ton of functions, manually or dynamically.
Here's my idea, and the design could be modified so filters are chainable:
<?php
class ItemsFilter
{
protected $items = array();
public function __construct($items) {
$this->items = $items;
}
public function byColor($color)
{
$items = array();
foreach ($this->items as $item) {
// I don't like this: I would prefer each item was an object and had getColor()
if (empty($item->color) || $item->color != $color)
continue;
$items[] = $item;
}
return $items;
}
}
$items = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$filter = new ItemsFilter($items);
$greens = $filter->byColor('green');
echo '<pre>';
print_r($greens);
echo '</pre>';
If you need more arguments you could use this function:
function splitArray($array, $params) {
$result = array();
foreach ($array as $item) {
$status = true;
foreach ($params as $key => $value) {
if ($item[$key] != $value) {
$status = false;
continue;
}
}
if ($status == true) {
$result[] = $item;
}
}
return $result;
}
$greensAndID1 = splitArray($o, array('color' => 'green', 'id' => 1));

Categories