Increment the key on a multidimensional array - php

I have the following php array:
$month = array (
'weeks'=> array(
'w1'=> array(
'd1'=> 'day one',
'd2'=> 'day two',
'd3'=> array(
'H1' => 'hour one',
'H2' => 'hour two'
)
),
'w2'=> array(
'd1'=> 'day one',
'd2'=> 'day two'
)
)
);
I want to recursively iterate over the array and change the keys to reflect an incremented time from the start of the month. Like so (simplified):
$month = array (
'weeks'=> array(
'1'=> array(
'1'=> 'day one',
'2'=> 'day two',
'3'=> array(
'3' => 'hour one',
'4' => 'hour two'
)
),
'5'=> array(
'5'=> 'day one',
'6'=> 'day two'
)
)
);
Note: the counter is NOT incremented as it steps down to a child. This reflects that the start time for a Week and the start time for its First Day both share the same timestamp. The counter increments for the next sibling AND the counter increments after a 'key/value' pair has no children.

This is an example of 'nested arrays' with the output array exactly matching the structure of the input. The only difference is that the array keys are turned into 'almost' incrementing integer subscripts.
The 'almost' part comes from the fact that when 'nesting' down one level the first entry has the same subscript as the previous level.
The way i approached this is to use a recursive function, which will deal with the 'nesting', and a 'foreach' loop within each 'level as each entry in the array remains at the same 'level' in the output.
Output: This needs to contain many levels, rather than storing a path of subscripts to the current output 'level, i just pass an array 'by reference' that can be simply set by the appropriate code.
The code: running with the given input using PHP 5.3.19 at 'viper-7'
First the function that does the work:
Note: the $destWeeks and $idxNew variables are passed as 'references' this allows the code to amend them directly.
function reindexWeeks($sourceWeeks, &$destWeeks, &$idxNew)
{
foreach($sourceWeeks as $sourceKey => $sourceValue) {
if (is_array($sourceValue)) {
$destWeeks[$idxNew] = array();
reindexWeeks($sourceValue, $destWeeks[$idxNew], $idxNew);
}
else {
$destWeeks[$idxNew] = $sourceValue;
$idxNew++;
}
}
}
Calling code:
$idxNew = 1; // starting index.
$newWeeks = array(); // output array at the 'week' level
reindexWeeks($month['weeks'], $newWeeks, $idxNew); // re-index the array
// output array..
$newMonth = array('weeks' => $newWeeks);
Output using the example provided in the question:
Array
(
[weeks] => Array
(
[1] => Array
(
[1] => day one
[2] => day two
[3] => Array
(
[3] => hour one
[4] => hour two
)
)
[5] => Array
(
[5] => day one
[6] => day two
)
)
)

Related

PHP order by value of array key

I have an array being created which contains a date:
$arr = array();
$arr["one"][] = array(
'due' => '17-01-2021 10:00:00',
);
$arr["one"][] = array(
'due' => '17-01-2021 09:00:00',
);
$arr["two"][] = array(
'due' => '19-01-2021 09:00:00',
);
$arr["two"][] = array(
'due' => '18-01-2021 09:00:00',
);
And I want to order by the value of the 'due' key
I tried adding this uasort function:
uasort($arr, function ($a, $b) {
return $a["due"] <=> $b["due"];
});
print_r($arr);
But that still shows in the order above, whereas it should be showing the '09:00:00' value first
Your approach wasn't really that far off, I basically just changed a few little things:
Loop over each "word-number-indexed" array individually (those indexed under one and two in the main array $arr).
Convert the due dates/times to unix timestamps to have an integer that can be compared. Without this, PHP tries to sort the strings on a character-by-character basis which does not work with your format but would work if your format was YYYY-MM-DD hh:mm:ss (because the "biggest" position value would be at the start).
Use usort instead of uasort since there is no point in keeping the keys (which are integers to begin with and neither one nor due in this context.
$arr = array();
$arr["one"][] = array(
'due' => '17-01-2021 10:00:00',
);
$arr["one"][] = array(
'due' => '17-01-2021 09:00:00',
);
$arr["two"][] = array(
'due' => '19-01-2021 09:00:00',
);
$arr["two"][] = array(
'due' => '18-01-2021 09:00:00',
);
foreach ($arr as &$numberIndex) {
usort($numberIndex, function ($a, $b) {
return strtotime($a["due"]) <=> strtotime($b["due"]);
});
}
print_r($arr);
Some side notes:
Note the & at &$numberIndex, without this PHP works on an in-place copy of your value and it is never changed in $arr.
This approach with strototime() only works if all your dates/times are after epoch time 0 (which is 1st of January 1970). If you need to use older dates you can create DateTime() objects within the sort callback.
The resulting array looks like this:
Array
(
[one] => Array
(
[0] => Array
(
[due] => 17-01-2021 09:00:00
)
[1] => Array
(
[due] => 17-01-2021 10:00:00
)
)
[two] => Array
(
[0] => Array
(
[due] => 18-01-2021 09:00:00
)
[1] => Array
(
[due] => 19-01-2021 09:00:00
)
)
)

I need to compare specific elements of a multi-dim PHP array with certain other elements in the same array

I have an array that contains certain words from a MySQL database, which are matched with words in a line of text. The text is, say, 20 lines long.
The array also stores the position of each word in the database, and some of these words are "related" to other words in the database, which are also stored in the array. It looks a bit like this:
$words = array(
["Line0"] => array (
["Word0"] => array(
["Name"] => "RandomWord",
["DatabasePos"] => 15,
["RelationsInDatabase"] => array (
89, //So this is clearly the same database pos as Word1 on Line0.
27, //let's assume there's a word on line15 that has this database pos
)
),
["Word1"] => array (
["Name"] => "SomeOtherRandomWord",
["DatabasePos"] => 89,
["RelationsInDatabase"] => array (
NULL
)
)
),
["Line1"] => array (
["Word0"] => .... ,
..
...
...
)
);
etc.
I want to iterate through this array, and find the words that are related to by other words. Then, append to the same array which lines and which words they are related to. For example:
$words = array(
["Line0"] => array (
["Word0"] => array(
["Name"] => "RandomWord",
["DatabasePos"] => 15,
["RelationsInDatabase"] => array (
89, //So this is clearly the same database pos as Word1 on Line0.
27, //let's assume there's a word on line15 that has this database pos
),
["RelationsInLinesOfText"] => array ( //I want to loop through and add this element to the array.
[0] => array("Line0", "Word1"),
[1] => array("Line15", "Word3")
)
),
["Word1"] => array (
["Name"] => "SomeOtherRandomWord",
["DatabasePos"] => 89,
["RelationsInDatabase"] => array (
NULL
)
)
),
["Line1"] => array (
["Word0"] => .... ,
..
...
...
)
);
My problem is that I end up with a very messy, 4/5 level deep "foreach" loop and end up making a bunch of mistakes that are hard to debug due to the messy code. Is there a clean way of doing this, maybe using something like a RecursiveArrayIterator? I don't have much experience with PHP iterator objects.
Thanks for the help
It is an ugly solution, but I think in any case you'll need to iterate through entire array twice-nested:
function searchLink($iLink, &$rgData)
{
$rgResult = [];
foreach($rgData as $sLine=>$rgLines)
{
foreach($rgLines as $sWord=>$rgWord)
{
if($rgWord['DatabasePos']==$iLink)
{
$rgResult[]=['line'=>$sLine, 'word'=>$sWord];
}
}
}
return $rgResult;
}
//$rgData is a data array
foreach($rgData as $sLine => $rgLines)
{
foreach($rgLines as $sWord=>$rgWord)
{
foreach($rgWord['RelationsInDatabase'] as $iPosition)
{
$rgData[$sLine][$sWord]['RelationsInLinesOfText'][]=searchLink($iPosition, $rgData);
}
}
}
also, since you've not mentioned if position is unique, an array ['line'=>$sLine, 'word'=>$sWord] will be written to each entry.

php array remove key and shift values up

I've researched topics similar to this but not exactly what I'm looking to do.
I have a multidimensional array like the following.
[code] => BILL
[assets] => Array
(
[en] => Array
(
[datatype] => My Assets
[data] => Array
(
[Corporate Equity] => 41
[Global Equity] => 24
[Fixed Income – Government] => 22
[Fixed Income – Corporate] => 8.1
[Other] => 3.57
)
)
)
I'd like to remove the first inner array, but preserve the values. Shift them up one level in the array so that it looks like this.
[code] => BILL
[assets] => Array
(
[datatype] => My Assets
[data] => Array
(
[Corporate Equity] => 41
[Global Equity] => 24
[Fixed Income – Government] => 22
[Fixed Income – Corporate] => 8.1
[Other] => 3.57
)
)
This is just the beginning of the array, there are other instances of the same key [en] at the same level.
I've tried unset, array_shift and others but I need to keep the contents of [en], just shift them up one level in the array.
You can use array_map which returns an array which contains all elements of the previous array after applying the function.
In this case it will simply take the array at index en and add it's contents to the new array.
http://php.net/manual/en/function.array-map.php
$arr = array('assets' => array(
'en' => array(
'datatype' => 'My Assets',
'data' => array(
'Corporate Equity' => 41,
'Global Equity' => 24,
'Fixed Income – Government' => 22,
'Fixed Income – Corporate' => 8.1,
'Other' => 3.57
)
)
));
$new_arr = array_map(function ($e) {
return $e['en'];
}, $arr);
A simple solution that assumes the key to always be en and the subkeys to always be (only) datatype and data:
$assets['datatype'] = $assets['en']['datatype'];
$assets['data'] = $assets['en']['data'];
unset( $assets['en'] );
This code could be problematic for you in the future if that array structure ever changes (it lacks extensibility), but it gets you what you want given the information you have provided.
array_shift is the opposite of array_pop. Used in stack/queue like structures for removing the fist element http://php.net/manual/en/function.array-shift.php
What you want to do is flatten the array. But if you want to keep all the other sub-arrays as you mentioned, you might look up array_merge.
I faced the same scenario after using reader to read xml file, the returned array was having inserted 0 key array in each level like the following one:
'config' =>
0 =>
'products' =>
0 =>
'media' =>
.
.
.
so I built a small function to get rid of a specific key and shift up its child's in a two dimensions array, in my case the key was 0. hopping this would help somebody also.
public function clearMaps(&$maps, $readerMaps, $omittedKey)
{
if (is_array($readerMaps)) {
foreach ($readerMaps as $key => $map) {
if ($key !== $omittedKey) {
$maps[$key] = [];
$this->clearMaps($maps[$key], $readerMaps[$key], $omittedKey);
} else {
$this->clearMaps($maps, $readerMaps[$key], $omittedKey);
}
}
} else {
$maps = $readerMaps;
}
}
// $maps: cleaned array, will start as empty array
// $readerMaps: array needs to be cleaned
// $omittedKey: array key to git rid of.
// first call is clearMaps([], $readerMaps, 0);

Fetching a multidimensional array

I am trying to edit a plugin that is fetching a multidimensional array, then breaking it out into a foreach statement and doing stuff with the resulting data.
What I am trying to do is edit the array before it gets to the foreach statement. I want to look and see if there is a key/value combination that exists, and if it does remove that entire subarray, then reform the array and pass it to a new variable.
The current variable
$arrayslides
returns several subarrays that look like something like this (I remove unimportant variables for the sake of briefness):
Array (
[0] => Array (
[slide_active] => 1
)
[1] => Array (
[slide_active] => 0
)
)
What I want to do is look and see if one of these subarrays contains the key slide_active with a value of 0. If it contains a value of zero, I want to dump the whole subarray altogether, then reform the multidimensional array back into the variable
$arrayslides
I have tried a few array functions but have not had any luck. Any suggestions?
$arrayslides = array(0 => array ( 'slide_active' => 1, 'other_data' => "Mark" ),
1 => array ( 'slide_active' => 0, 'other_data' => "ABCDE" ),
2 => array ( 'slide_active' => 1, 'other_data' => "Baker" ),
3 => array ( 'slide_active' => 0, 'other_data' => "FGHIJ" ),
);
$matches = array_filter($arrayslides, function($item) { return $item['slide_active'] == 1; } );
var_dump($matches);
PHP >= 5.3.0
I know its not so efficient but still
foreach ($arraySlides as $key => $value)
{
if(in_array('0', array_values($value))
unset($arraySlides[$key]);
}

insert value at the beginning of an array in php

my array is
$hello= array( Code => 'TIR', Description => 'Tires', Price => 100 )
now i want to add a value in array beginning of an array not the end of an array.... and results i want is
$hello= array( ref=>'World', Code => 'TIR', Description => 'Tires', Price => 100 )
UPDATE
actually i need any value that is coming will be added in the beginning of an array....this is not single value.. ref=world.... this is coming from output...like if i add quantity=50, then it should be added beginning of an array before 'ref' an array should be
$hello= array(quantity=>'50', ref=>'World', Code => 'TIR', Description => 'Tires', Price => 100 )
I would use array_merge()
Merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one. It returns the resulting array.
$hello = array ("Code" => "Tir" .....); // you should really put quotes
// around the keys!
$world = array ("ref" => "World");
$merged = array_merge($world, $hello);
You can use the + operator:
$hello = array( 'Code' => 'TIR', 'Description' => 'Tires', 'Price' => 100 );
$hello = array('ref' => 'World') + $hello;
print_r($hello);
would give
Array
(
[ref] => World
[Code] => TIR
[Description] => Tires
[Price] => 100
)
Like Pekka said, you should put quotes around the keys. The PHP manual explicitly states omitting quotes is wrong usage. You might also want to check out my answer about the difference between using the + operator vs using array_merge to decide which you want to use.
$a= array( 'a' => 'a' );
$b = array( 'b' => 'b' );
$res = $b + $a;
//result: ( 'b' => 'b', 'a' => 'a' )
$hello = array_merge(array('ref'=>'World'), $hello);

Categories