How can I convert the below array to look like the one right below. I am trying to use array_map but i am confused on how to write the function.
array(3) {
["award_year"]=>
array(2) {
[0]=>
string(7) "1999-01"
[1]=>
string(7) "2010-02"
}
["award_title_user"]=>
array(2) {
[0]=>
string(1) "2"
[1]=>
string(2) "tt"
}
["award_description_user"]=>
array(2) {
[0]=>
string(1) "2"
[1]=>
string(3) "ddd"
}
}
This what i am trying to achieve:
array(2) {
[0]=>
array(3) {
["award_year"]=>
string(7) "2010-02"
["award_title_user"]=>
string(2) "tt"
["award_description_user"]=>
string(3) "ddd"
}
[1]=>
array(3) {
["award_year"]=>
string(7) "1999-01"
["award_title_user"]=>
string(1) "2"
["award_description_user"]=>
string(1) "2"
}
}
$newArr = [];
foreach($oldArr as $key=>$row) {
foreach($row as $index=>$item) {
$newArr[$index][$key] = $item;
}
}
this will solve it, but no checks if data is valid as you mentioned
First things first, #tzook-bar-noy's answer is a better answer in this case, and I am not even advocating the approach I am going to detail here.
When dealing with arrays, I always try to avoid generic loops (ie: foreach()) if I can, instead using the more functional-programming approach that you mention in your question: using functions like array_map(). However the functional-programming functions are very focused in what they do (which is their benefit: they make your code Cleaner), so to use them: you kinda gotta be wanting to do the specific operation they offer.
array_map() has a drawback for your purposes here, in that the mapped array has the same keys in the same order as the original array, which is not what you want here. You need to both turn your original array "inside out", but the ordering of the resultant array you want is the reverse of the original data. Not a good fit for array_map().
It's doable with array_map(), but it's like using a flathead screwdriver when you really need a Philips.
Here's an example:
<?php
$awards = [
"award_year" => ["1999-01", "2010-12"],
"award_title_user" => ["2", "tt"],
"award_description_user" => ["2", "ddd"]
];
$remappedAwards = array_map(function($year, $title, $description){
return [
"award_year" => $year,
"award_title_user" => $title,
"award_description_user" => $description
];
}, $awards["award_year"], $awards["award_title_user"], $awards["award_description_user"]);
$remappedAwards = array_reverse($remappedAwards);
echo "<pre>";
var_dump($remappedAwards);
echo "</pre>";
Obviously I've hardcoded the key names in here too which is less than ideal. One could contrive a generic approach, but by then we'd be so far beyond the actual intent of aaray_map() that the code complexity would be getting daft.
In other languages wherein these array-iteration functions are a bit better implemented (say JS or CFML) one might be able to come up with a half-decent answer with a .reduce() (JS, CFML) kind of operation. However PHP's array_reduce() (and its other array-iteration methods) are hamstrung by their poor implementation as they only pass the value to the callback. They really need to pass at least the index as well, and (less-often-useful, but handy sometimes ~) the array itself as additional arguments to make them anything more than a proof-of-concept. IMO, obviously (I'm biased, I do more JS & CFML than I do PHP, so my expectations are set higher).
Bottom line: array_map() was not a good fit for your requirement here, but I applaud your efforts for thinking to us it as the function-programming approach to array manipulation is definitely a better approach than generic looping where the requirement matches the functionality.
Related
Here is an extract of my test code and data:-
//Update Array
$civs[1][1]="1";
$civs[1][2]="Inca";
$civs[2][1]="2";
$civs[2][2]="India";
//Sort Array
array_multisort($civs[0][2], SORT_DESC, SORT_STRING,
$civs[0][1], SORT_NUMERIC, SORT_DESC);
Output:-
Warning: array_multisort(): Argument #1 is expected to be an array or
a sort flag in ~/test.php on line 3
array(3) { [1]=> array(2) { [1]=> string(1) "1" [2]=> string(4) "Inca" } [2]=> array(2) { [1]=> string(1) "2" [2]=> string(5) "India" } [0]=> array(2) { [2]=> NULL [1]=> NULL } }
Problem statement
Depending on what the User selects I need to sort the array in PHP either on the 1st (numeric) or 2nd (alphanumeric) element of the 2nd part of the array but can't see how to do that, the various PHP sorts don't seem to allow you to tell it what is to be sorted on, have tried the above code . The PHP Manual for uksort says "If the array you wish to sort needs to be sorted by some non-trivial criteria," well numeric is about as trivial as it gets!
I've been looking at this for a couple of hours now and am sure I must be missing something as all I can see is that I have to write a custom function but surely PHP knows how to do simple sorts based on numeric or text values?
Main question I found was this:- How can I sort arrays and data in PHP? and I also spent a fair bit of time browsing through http://php.net/manual/en/array.sorting.php.
Apologies if I have missed something obvious.
I am dealing with arrays whose structure is different depending on the number or items in the array.
For example, the following is the array with one item in it.
// Case #1
["Assignment"]=>
object(stdClass)#29 (9) {
["Id"]=> string(10) "1234567890"
..
}
However if there are more than 1 item in the array,
// Case #2
["Assignment"]=>
array(2) {
[0]=>
object(stdClass)#28 (9) {
["Id"]=> string(10) "1234567890"
..
}
[1]=>
object(stdClass)#28 (9) {
["Id"]=> string(10) "1234567890"
..
}
}
Notice that the contents are in another array for this. No matter of how many items there are, I want to access the Id. $array->Id will work for one case but won't work for the other with the error saying, Trying to get property of non-object.
I could come up with an inefficient way by counting the # of contents in the array like this:
// say the arrays above are declared as $assignment
if($numOfAssignment > 1) {
foreach($assignment as $key) {
echo $key->Id;
}
}
else {
echo $assignment->Id;
}
But if the code was a bit lengthy, I feel it is too repetitive and inefficient.
Is there a way to do this in one effective phrase no matter of the number of the contents inside the array? Let me know if anything is unclear. Thanks!
What you can do is change the non-array into an array with a single element, then you can process it consistently.
if (!is_array($assignment)) {
$assignment = array($assignment);
}
foreach ($assignment as $key) {
echo $key=>Id;
}
SO,
I have an issue with determining recursion in arrays in PHP. Assume that I have a dynamic-generated array, which finally can looks like:
$rgData = [
['foo', 'bar', $rgTemp=[7, 31, true]],
[-5, &$rgData, 'baz']
];
(links to variables here are provided dynamically and may refer to an array itself). Another sample:
$rgData = [
['foo', 'bar', $rgTemp=[7, 31, true]],
[-5, &$rgTemp, 'baz']
];
Both arrays have some references inside, but second looks good since it's reference is not cycled. Later, due to my logic, I have to handle array via recursive functions (something like array_walk_recursive) - and, of cause, I got Fatal error due to infinite nested array recursion in case of first sample above.
My question is - how to determine if an array has infinite recursion. Note, that this question is more complicated than simple search link from inside array to itself, because we can have something like:
$rgOne = [
['foo', 'bar'],
['baz']
];
$rgTwo = [6, 'test', &$rgOne];
$rgOne[1][] = &$rgTwo;
i.e. more complicated recursion. I found that PHP can resolve this somehow in var_dump and similar functions - for example, dump of the third sample will look like:
array(2) {
[0]=>
array(2) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
}
[1]=>
array(2) {
[0]=>
string(3) "baz"
[1]=>
&array(3) {
[0]=>
int(6)
[1]=>
string(4) "test"
[2]=>
&array(2) {
[0]=>
array(2) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
}
[1]=>
*RECURSION*
}
}
}
}
i.e. *RECURSION* was caught. Currently, I've tried to resolve a matter via function:
function isLooped(&$rgData, &$rgCurrent=null)
{
foreach($rgData as $mKey=>$mValue)
{
if(is_array($mValue) && isset($rgCurrent) &&
$rgCurrent===$rgData /* that's where, it seems, I need help*/)
{
return true;
}
elseif(is_array($mValue) && isLooped($mValue, $rgData))
{
return true;
}
}
return false;
}
but with no success (and I know why - that comparison is invalid). The only idea I have now is to do weird thing, like:
function isLooped(&$rgData)
{
$rgTemp = #var_export($rgData, 1);
return preg_match('/circular references/i', error_get_last()['message']);
}
but that is sad since I need at least copy my array data to some temporary storage (and, besides, all of this looks like a glitch, not a proper solution). So, may be there are some ideas of how to do that normal way?
Update: I've found a solution via changing key in the array and then looking for it in recursive loop. This is much better than var_* functions, but still not exactly what I want. Is there a way to do this without var_* functions or changing original array?
The problem is that PHP doesn't have a mechanism to tell you whether two variables reference the same zval (internal data type representing the actual held data). This rules out keeping track of the variables you have traversed so far as a solution.
Without this feature or modifying elements (pin method) it's unfortunately not possible to detect a recursive data structure except for var_dump() or print_r() hacks.
I have a nested array of arrays, and I want to shuffle the inner arrays. My code looks like this (simplified):
$a = array(array('banana', 'peach'), array('ding', 'dong'), array('oh snow'));
foreach ($a as &$arr) {
shuffle($arr);
}
var_dump($a);
The var_dump outputs this:
array(3) { [0]=> array(2) { [0]=> string(5) "peach" [1]=> string(6) "banana" } [1]=> array(2) { [0]=> string(4) "ding" [1]=> string(4) "dong" } [2]=> &array(1) { [0]=> string(7) "oh snow" } }
As you can see in the output, the first two subarrays work, but the third subarray is linked by reference in the output...
In my full app, this last array-link causes problems, but rather than working around the issue, I want to fix this shuffle thing...
Cheers!
This has to do with how PHP stores references to array elements. It cannot reference an element of an array, only values. Therefore it has to store the value array('oh snow') in a "slot" of the symbol table, then make $arr and $a[2] a reference to that value.
To fix this, unset($arr) after the loop. That way only a single variable is referencing the value, which will then be made a regular array index again. Unsetting references after a foreach is good practice anyway, since there are many such gotchas.
I have one object being the result of a database query, looking something like this (var_dump output):
object(stdClass)#17 (6) {
["id"]=>
string(1) "1"
["title"]=>
string(20) "Some Title"
["description"]=>
string(41) "Some really good stuff. Description here."
["slug"]=>
string(19) "some-slug-url"
["picture_url"]=>
NULL
["price"]=>
string(4) "5.99"
}
I just need all property values "transferred" to a different class which has the same property names. Is there a simple way to do this?
Take a look at PHP's get_object_vars()-function to achieve the desired effect without tons of assignment statements:
foreach (get_object_vars($sourceObject) as $name => $value) {
$destinationObject->$name = $value;
}
You should make sure that you add sufficient error-checking to this, depending on your needs.
The simple and "failsafe" solution
$target = new MyClass;
$target->id = $source->id;
$target->title = $source->title;
// and so on
Its a little bit more to code, but the benefits are
If some property of $source change, you will notice it (because its missing in $target)
You can name the properties of $target completely independent from $source
You see, what happens