Efficient way to sort an array? - php

I have an array of variabel length, containing events sorted by startdate, looking like this:
Array
(
[0] => stdClass Object
(
[id] => 1978
[date] => 2012-09-29
)
[1] => stdClass Object
(
[id] => 1979
[date] => 2012-10-14
)
...etc....
I need to make a function that takes one of the event, and puts in the middle of a new array with a length of exactly seven, and puts the event's neighbours on each side.
So if event 5 passed to the function, the output should be:
[2][3][4][5][6][7][8]
If the first event is passed to the function, and the original amount of events is 12, the output should be:
[10][11][12][1][2][3][4]
If the orignal amount of events is 6, and the fifth event is passed, the output should be:
[2][3][4][5][6][1][]
So the list of events should always "wrap around" in the new array and fill it up as much as possible.
I have hacked together a solution, that involves quite a bit of steps. I dont really like it, and it got me wondering:
How would this be done in the most efficient and elegant way?

You need to change the values in this codes
define('TO_SHOW',7); // number of items to show in your case it is 7
$selected = 1; //// which one you need need at center.
and your array;
Execute this and try :
<?php
define('TO_SHOW',7); // number of items to show in your case it is 7
function change_order($arry, $sel){
$arr_cnt = count($arry);
$shift_count = $arr_cnt - (ceil(TO_SHOW/2)-$sel);
for($i=0; $i<$shift_count; $i++){
array_push($arry, array_shift($arry));
}
return array_slice($arry, 0, TO_SHOW);
}
$arr = array(array(
"id" => 1,
"date" => 2012-09-29
),
array(
"id" => 2,
"date" => 2012-09-29
),
array(
"id" => 3,
"date" => 2012-09-29
),
array(
"id" => 4,
"date" => 2012-09-29
),
array(
"id" => 5,
"date" => 2012-09-29
),
array(
"id" => 6,
"date" => 2012-09-29
),
array(
"id" => 7,
"date" => 2012-09-29
),
array(
"id" => 8,
"date" => 2012-09-29
),
array(
"id" => 9,
"date" => 2012-09-29
),
array(
"id" => 10,
"date" => 2012-09-29
),
array(
"id" => 11,
"date" => 2012-09-29
),
array(
"id" => 12,
"date" => 2012-09-29
),
array(
"id" => 13,
"date" => 2012-09-29
),
array(
"id" => 14,
"date" => 2012-09-29
)
);
$selected = 1; //// centre one
$test = change_order($arr, $selected);
echo "<pre>";
print_r($test);
?>

Related

Array_slice in multidimensional array? But a different output

I have an array in php like this :
$multid_array = array(
"url" => "www.checkmyhouse.cpm",
"date" => "2019/12/12",
"minor" => 1,
"sittingroom" => 1,
"dinningroom" => 2,
"toilet" => 2,
"parking" => 1,
"bedroom" => 2,
"garage" => 2,
"rooms" => 4,
"garden" => 1,
"url_1" => "-sameurl-",
"date_1" => "2019/12/3",
"minor_1" => 3,
"sittingroom_1" => 2,
"dinningroom_1" => 2,
"toilet_1" => 3,
"parking_1" => 1,
"bedroom_1" => 2,
"garage_1" => 6,
"rooms_1" => 6,
"garden_1" => 1,
"url_2" => "-sameurl-",
"date_2" => "2019/12/5",
"minor_2" => 3,
"sittingroom_2" => 2,
"dinningroom_2" => 2,
"toilet_2" => 3,
"parking_2" => 1,
"bedroom_2" => 5,
"garage_2" => 6,
"rooms_2" => 9,
"garden_2" => 1,
);
I have searched around, found this link. but not been able to figure it out. keep getting close.
array_slice in multidimensional array?
This is the output I would like:
$array =
[
"levels" => array(
"0" => array(
"url" => "www.checkmyhouse.cpm",
"date" => "2019/12/1",
"minor" => 1,
"sittingroom" => 1,
"dinningroom" => 2,
"toilet" => 2,
"parking" => 1,
"bedroom" => 2,
"garage" => 2,
"rooms" => 5,
"garden" => 1,
),
"1" => array(
"url" => "-sameurl-",
"date" => "2019/12/3",
"minor" => 3,
"sittingroom" => 2,
"dinningroom" => 2,
"toilet" => 3,
"parking" => 1,
"bedroom" => 2,
"garage" => 6,
"rooms" => 6,
"garden" => 1,
),
"2" => array(
"url" => "-sameurl-",
"date" => "2019/12/5",
"minor" => 3,
"sittingroom" => 2,
"dinningroom" => 2,
"toilet" => 3,
"parking" => 1,
"bedroom" => 5,
"garage" => 6,
"rooms" => 9,
"garden" => 1,
)
)
];
Just trying to rearrange it. but I have used array_slice and could only get the output of the first 9 elements.
array_splice($multid_array,9);
But I want to run it automatically, so in case more information gets added into the array then it would still work
Why not use simple for loop: (in this case you can have various number of field in each array and they don't need to be fixed as when use array_chunk)
$multid_array = array("url" => "www.checkmyhouse.cpm","date" => "2019/12/12","url_1" => "-sameurl-","date_1" => "2019/12/3","url_2" => "-sameurl-","date_2" => "2019/12/5",);
$ans = [];
foreach($multid_array as $k => $v) {
$parts = explode("_", $k);
$pk = 0; //default as 0 as when no prefix set to key "0"
if (count($parts) > 1) { // check if has suffix
$pk = $parts[1];
$k = $parts[0];
}
if (!isset($ans[$pk]))
$ans[$pk] = []; // init array if first time
$ans[$pk][$k] = $v;
}
Now $ans will contain your data - you can add "levels" key if you wish.
This will only works if you have "_" saved to mark inner indexes and they are not used in the actual keys

How to find a specific element in array (by last modification date and product id)?

Here is an array with TWO products. The difference between them is in price and last modification date.
$array = array(
"0" => array
(
"id" => 1,
"name" => apple,
"product_price" => 5,
"date_and_time" => 2017-11-01
),
"1" => array
(
"id" => 1,
"name" => apple,
"product_price" => 6,
"last_mod_date" => 2017-11-02
),
"2" => array
(
"id" => 2,
"name" => orange,
"product_price" => 4,
"last_mod_date" => 2017-11-03
),
"3" => array
(
"id" => 2,
"name" => orange,
"product_price" => 3,
"last_mod_date" => 2017-11-04
));
My question is how to build a new array for each product in array, where the last modification date has a max value? So, I need to compare each product in array in terms of modification date and then push them to new array ( $products = array(); )
So I'd like to receive an array where:
An apple where price is equal to six and date is 2017-11-02, because
the date is greater than date where the price is equal to five,
and orange where the pice is equal to three and the date is
2017-11-04, because the date is greater than date where price is
equal to four
In this case it should look like:
$products = array(
"0" => array
(
"id" => 1,
"name" => apple,
"product_price" => 6,
"last_mod_date" => 2017-11-02
),
"1" => array
(
"id" => 2,
"name" => orange,
"product_price" => 3,
"last_mod_date" => 2017-11-04
));
Many thanks for your support.
Here is an approach that provides very little informational or educational value but leverages PHP native array functions.
<?php
function getLatestById($id, $data) {
foreach ($data as $key => $row) {
$idColumn[$key] = $row['id'];
$modifiedColumn[$key] = $row['modified'];
}
array_multisort($idColumn, SORT_ASC, $modifiedColumn, SORT_DESC, $data);
$k = array_search(1, array_column($data, 'id'));
return $data[$k];
}
$foo = [];
$foo[] = ['id' => 1, 'modified' => '2017-11-01', 'price' => 5];
$foo[] = ['id' => 1, 'modified' => '2017-11-02', 'price' => 6];
$foo[] = ['id' => 2, 'modified' => '2017-11-03', 'price' => 4];
$foo[] = ['id' => 2, 'modified' => '2017-11-04', 'price' => 3];
var_dump(getLatestById($id, $foo));
So the thinking is, sort by id, then sort by modified. Once you've got a sorted array you would just snag the first occurrence by ID.
For more illustrative code I'd probably write a loop, in it populate a new array using ID as the index. Compare existing value against one iterating on, if modified greater (more recent) overwrite. Something like...
$foo = [];
$foo[] = ['id' => 1, 'modified' => '2017-11-01', 'price' => 5];
$foo[] = ['id' => 1, 'modified' => '2017-11-02', 'price' => 6];
$foo[] = ['id' => 2, 'modified' => '2017-11-03', 'price' => 4];
$foo[] = ['id' => 2, 'modified' => '2017-11-04', 'price' => 3];
$a = [];
foreach ($foo as $k => $v) {
if (empty($a[$v['id']]) || $a[$v['id']]['modified'] < $v['modified']) {
$a[$v['id']] = $v;
}
}
var_dump($a);
Or leverage your database and don't do this in code.

Add new array values to existing array position

I have array which is presenting like this:
$array = array (
"list" => array(
"serwer-1" => 3
),
"servers" => array(
3 => array(
"msg" => "{'some data': 123123121313}",
"status" => 200
),
),
);
I want add new items to $array['list'] for example:
array (
"list" => array(
"serwer-1" => 3
//NEW DATA HERE
"serwer-2" => 7,
),
"servers" => array(
3 => array(
"msg" => "{'some data': 123123121313}",
"status" => 200
),
),
);
Maybe it's trivial, but I haven't any idea how to do this - I have bad day today :(
In order to add a key-value pair to an existing array just do it like the key exists there.
$array["list"]["serwer-2"] = 7;
Then you will get desired result.

PHP - structure multidimensional array depending on values

I have an array:
$initialarray = array(
0 = array(
'unit' => 1,
'class' => 1,
'value' => 'string1'
),
1 = array(
'unit' => 1,
'class' => 2,
'value' => 'string2'
),
2 = array(
'unit' => 1,
'class' => 2,
'value' => 'string3'
),
3 = array(
'unit' => 2,
'class' => 1,
'value' => 'string4'
)
4 = array(
'unit' => 2,
'class' => 2,
'value' => 'string5'
)
);
What would be the best way to structure it (to group the resulting sub-arrays) depending first on the 'unit' field's values, and then depending on the 'class' field's values, like so:
$resultarray = array(
// array of all the sub-arrays of 'unit' = 1
$unit[1] = array(
// array of all the sub-arrays of 'unit' = 1 and 'class' = 1
$class[1] = array(
0 = array(
'unit' => 1,
'class' => 1,
'value' => 'string1'
)
)
// array of all the sub-arrays of 'unit' = 1 and 'class' = 2
$class[2] = array(
0 = array(
'unit' => 1,
'class' => 2,
'value' => 'string2'
),
1 = array(
'unit' => 1,
'class' => 2,
'value' => 'string3'
)
)
)
// array of all the sub-arrays of 'unit' = 2
$unit[2] = array(
// array of all the sub-arrays of 'unit' = 2 and 'class' = 1
$class[1] = array(
0 = array(
'unit' => 2,
'class' => 1,
'value' => 'string4'
)
)
// array of all the sub-arrays of 'unit' = 2 and 'class' = 2
$class[2] = array(
0 = array(
'unit' => 2,
'class' => 2,
'value' => 'string5'
)
)
)
)
I have asked a similar question here and got a working answer for only one iteration, i.e. for only structuring the array by one of the fields. But I could not make the same solution work for multiple iterations, i.e. for more than one field.
Also, is there a solution to structure a multidimensional array depending on more than two fields?
I think it's not a way of asking the question. It is very simple , you can do this by playing with arrays,keys and etc.... So first you should try hard for the problem. After If you have any problem in the middle of your tries then you can ask that here. I have solved your problem here is the complete code , but next time please do some work and then only post the problem. Never ask for the code.
foreach ($initialarray as $key1=>$val1)
{
foreach ($val1 as $key2=>$val2)
{
if($key2=='unit')
{
$num=$val2;
if($val2!=$num)
$testarr['unit'.$val2]=array();
}
if($key2=='class')
{
$testarr['unit'.$num]['class'.$val2][]=$val1;
}
}
}
print_r($testarr);
I must offer a better way for you and future researchers...
You only need one loop, and you merely need to nominate the result array's key values before using [] to "push" new data into the deepest subarray.
*there is absolutely no need for any condition statements or a second loop.
Code: (Demo)
$initialarray = [
['unit' => 1, 'class' => 1, 'value' => 'string1'],
['unit' => 1, 'class' => 2, 'value' => 'string2'],
['unit' => 1, 'class' => 2, 'value' => 'string3'],
['unit' => 2, 'class' => 1, 'value' => 'string4'],
['unit' => 2, 'class' => 2, 'value' => 'string5']
];
foreach ($initialarray as $row) {
$result[$row['unit']][$row['class']][] = $row;
}
var_export($result);
Output:
array (
1 =>
array (
1 =>
array (
0 =>
array (
'unit' => 1,
'class' => 1,
'value' => 'string1',
),
),
2 =>
array (
0 =>
array (
'unit' => 1,
'class' => 2,
'value' => 'string2',
),
1 =>
array (
'unit' => 1,
'class' => 2,
'value' => 'string3',
),
),
),
2 =>
array (
1 =>
array (
0 =>
array (
'unit' => 2,
'class' => 1,
'value' => 'string4',
),
),
2 =>
array (
0 =>
array (
'unit' => 2,
'class' => 2,
'value' => 'string5',
),
),
),
)
If I may express myself in the following manner: I only see the front-end of your problem and know nothing about its back-end, e.g. "Where does the data come from?", "How is it collected and stored", etc. so my answer might not be a real help but still I'll give my "tuppence".
If you can store all that data in a relational database (in form of table(s)) it would be much more easier and faster(!) to select the needed data from the database instead of rearranging arrays, which will take some more time in comparison.
Just as an example you might then select (and store it into an array) all items which have unit = '1' and / or all items which have class = '2'. That would make life much more easier IMHO, than having all the data in a multidimensional array and then try to sort it / rearrange it. Especially if you do that based on more than one property.

Nested array. Third level is disappearing

I have that array :
$a = array(
"7" => array(
"id" => 7,
"parent" => 6
),
"6" => array(
"id" => 6,
"parent" => 5
),
"5" => array(
"id" => 5,
"parent" => 4
),
"4" => array(
"id" => 4,
"parent" => 0
),
"3" => array(
"id" => 7,
"parent" => 2
),
"2" => array(
"id" => 7,
"parent" => 1
),
"1" => array(
"id" => 7,
"parent" => 0
)
);
the result that I want is that :
$a = array(
"4" => array(
"id" => 4,
"parent" => 0,
array(
"5" => array(
"id" => 5,
"parent" => 4,
array(
"6" => array(
"id" => 6,
"parent" => 5,
array(
"7" => array(
"id" => 7,
"parent" => 6
)
)
)
)
)
)
),
"2" => array(
"id" => 7,
"parent" => 1,
array(
"3" => array(
"id" => 7,
"parent" => 2
)
)
),
"1" => array(
"id" => 7,
"parent" => 0
)
);
the code that I use is this :
foreach($a as $v)
{
if(isset($a[$v['PARENT']]))
{
$a[$v['PARENT']][$v['ID']] = $v;
unset($a[$v['ID']]);
}
}
and the problem that I have is that I get that result :
$a = array(
"4" => array(
"id" => 4,
"parent" => 0,
array(
"5" => array(
"id" => 5,
"parent" => 4
)
)
),
"2" => array(
"id" => 7,
"parent" => 1,
array(
"3" => array(
"id" => 7,
"parent" => 2
)
)
),
"1" => array(
"id" => 7,
"parent" => 0
)
);
instead of the need it result.
To solve your problem you need to properly understand how variable referencing/aliasing in PHP works.
Look at the following example code, which does not look much different to yours but makes use of references in order to access any parent even it has already "moved":
# transform $flat into a tree:
foreach($flat as $id => &$value)
{
# check if there is a parent
if ($parentId = $value['parent'])
{
$flat[$parentId][0][$id] =& $value; # add child to parent
unset($flat[$id]); # remove reference from topmost level
}
}
unset($value); # remove iterator reference
print_r($flat); # your tree
$flat now contains all values from $flat - but reordered. Demo.
Are you sure that output array is correct? Surely the key 2 should be a child of 1 (since 2 has 'parent'=>1)? If this is not the case, I don't understand what are actually trying to do and how the keys all relate to each other.
If 2 should be a child of 1, this works:
$keep = array();
foreach ($a as $k => &$v) {
// Loop the array first time and create references to
// structure the array how you want it
if ($v['parent']) {
$a[$v['parent']][0] = array($k => &$v);
} else $keep[] = $k;
}
foreach ($a as $k => $v) {
// Loop it again to get rid of non-root nodes from the root
if (!in_array($k,$keep)) {
unset($a[$k]);
}
}
print_r($a);

Categories