Replace values in associative array - php

I'm consuming an API which returns an array of objects as this:
$base = array(
["orange","_","banana"],
["banana","_","_"],
["_","apple","kiwi"],
["_","raspberry","strawberry"]
);
And I intend to show "0" when key value is "_" however I haven't found a better way to do this than this:
foreach ($base as $key => $value) {
for ($i=0; $i<=3;$i++) {
if ($base[$key][$i]=="_")
$base[$key][$i]="0";
}
}
This works just fine since it's a simple demo but the real array is sometimes big and I've found this solution somewhat inefficient.
My question is, there's some php built-in function to do achieve this in or at least a better way to do this?
Thanks in advance guys,

Use array_walk_recursive(), pass the elements by reference and walk over the array, checking for the value _ - if its a match, replace it with 0.
$base = array(
["orange","_","banana"],
["banana","_","_"],
["_","apple","kiwi"],
["_","raspberry","strawberry"]
);
array_walk_recursive($base, function(&$v) {
if ($v === '_')
$v = 0;
});
Output becomes
Array
(
[0] => Array
(
[0] => orange
[1] => 0
[2] => banana
)
[1] => Array
(
[0] => banana
[1] => 0
[2] => 0
)
[2] => Array
(
[0] => 0
[1] => apple
[2] => kiwi
)
[3] => Array
(
[0] => 0
[1] => raspberry
[2] => strawberry
)
)
Live demo at https://3v4l.org/6Bs8ZE

You can replace _ with 0;
json_decode(str_replace('"_"','"0"',json_encode($base)));

Related

PHP Array rearrange numeric key as parrent key

i want to rearrange a simple multidimensional array.
Array
(
[pieces] => Array
(
[0] => 2
[1] => 9
)
[start] => Array
(
[0] => 0001
[1] => 9901
)
[end] => Array
(
[0] => 0002
[1] => 9909
)
[group] => Array
(
[0] => 0001-0100
[1] => 9901-9999
)
)
to
Array
(
[tokens] => Array
(
[0] => Array
(
[start] => 0001
[end] => 0002
[pieces] => 2
[group] => 0100
)
[1] => Array
(
[start] => 9901
[end] => 9909
[pieces] => 9
[group] => 9901-9999
)
)
)
I have tried something similar this:
$keys = array_keys($array);
foreach ($keys as $key => $val) {
foreach ($array as $k => $v){
foreach($array[$v] as $tk => $tv){
if($val == $k){
$new['tokens'][][$val] = $tv;
}
}
}
}
The numeric is the set of tokens which i prosted from my form,
Please can anyone explain me what i do wrong?
I am working some hours with different codes (i know the solution is very simple) but I am a little bit confused :/
Thank you very much!
BR KK
The Fourth Bird's solution is quite rigid in that it:
Requires an explicitly-defined key in the loop condition.
Enforces that the entire result has no more items than that one key has.
Assumes and enforces that the input keys are sequential and zero-indexed.
The below will work no matter what:
foreach( $array as $y => $inner ) {
foreach( $inner as $x => $value ) {
$new['tokens'][$x][$y] = $value;
}
}
Demo: https://3v4l.org/Rmdtd
Edit: I think it's worth preserving The Fourth Bird's explanation of the trouble with the posted code from his now-deleted answer:
You are trying to index into $array[$v], but $v in the case is one
of the sub arrays. According to the array
docs:
Arrays and objects can not be used as keys. Doing so will result in
a warning: Illegal offset type.
Make sure that you have error_reporting turned up to E_ALL while you're developing code so that you can see non-critical messages that indicate current and/or future problems.

merging array in CI 3

I want to merge two arrays in order to get the data as per my requirement.
I am posting my result, please have a look.
First array:
Array
(
[0] => Array
(
[km_range] => 300
[id] => 2
[car_id] => 14782
)
[1] => Array
(
[km_range] => 100
[id] => 3
[car_id] => 14781
)
[2] => Array
(
[km_range] => 300
[id] => 4
[car_id] => 14783
)
)
Second array:
Array
(
[0] => Array
(
[user_id] => 9c2e00508cb28eeb1023ef774b122e86
[car_id] => 14783
[status] => favourite
)
)
I want to merge the second array into the first one, where the value at key car_id matches the equivalent value; otherwise it will return that field as null.
Required output:
<pre>Array
(
[0] => Array
(
[km_range] => 300
[id] => 2
[car_id] => 14782
)
[1] => Array
(
[km_range] => 100
[id] => 3
[car_id] => 14781
)
[2] => Array
(
[km_range] => 300
[id] => 4
[car_id] => 14783
[fav_status] => favourite
)
)
Since the merge is so specific I would try something like this:
foreach ($array1 as $index => $a1):
foreach ($array2 as $a2):
if ($a1['car_id'] == $a2['car_id']):
if ($a2['status'] == "favourite"):
$array1[$index]['fav_status'] = "favourite";
endif;
endif;
endforeach;
endforeach;
You might be able to optimize the code more but this should be very easy to follow...
Another way to achieve this without using the index syntax is to reference the array elements in the foreach by-reference by prepending the ampersand operator:
foreach($firstArray as &$nestedArray1) {
foreach($secondArray as $nestedArray2) {
if ($nestedArray1['car_id'] == $nestedArray2['car_id']) {
$nestedArray1['fav_status'] = $nestedArray2['status'];
}
}
}
You can see it in action in this Playground example.
Technically you asked about merging the arrays. While the keys would be different between the input arrays and the desired output (i.e. "status" vs "fav_status"), array_merge() can be used to merge the arrays.
if ($nestedArray1['car_id'] == $nestedArray2['car_id']) {
$nestedArray1 = array_merge($nestedArray1, $nestedArray2);
}
Playground example.
Additionally the union operators (i.e. +, +=) can be used.
If you want to append array elements from the second array to the first array while not overwriting the elements from the first array and not re-indexing, use the + array union operator1
if ($nestedArray1['car_id'] == $nestedArray2['car_id']) {
$nestedArray1 += nestedArray1;
}
Playground example.
1http://php.net/manual/en/function.array-merge.php#example-5587

Passing multiple arrays to a Cartesian function

I need to pass multiple array's in an indexed format to a cartesain function in order to calculate every permutation. This works when the code is:
$count = cartesian(
Array("GH20"),
Array(1,3),
Array(6,7,8),
Array(9,10)
);
I will not always know the length, number of arrays, or values so they are stored in another array "$total" which may look something like this:
Array (
[0] => Array
(
[0] => 1
[1] => 3
)
[1] => Array
(
[0] => 6
[1] => 7
[2] => 8
)
[2] => Array
(
[0] => 9
[1] => 10
)
)
I have tried implementing the user_call_back_function as per:
$count = call_user_func('cartesian', array($total));
However the array that then gets passed looks like this:
Array (
[0] => Array (
[0] => Array (
[0] => Array (
[0] => 1
[1] => 3
[2] => 4
)
[1] => Array (
[0] => 5
[1] => 6
[2] => 7
[3] => 8
)
[2] => Array (
[0] => 9
[1] => 10
)
)
)
)
Where am I going wrong, why is the array being buried further down in dimensions where it is not needed, and is this the reason why my cartesain function does no longer work?
Thanks, Nick
As requested, here is my cartesain function:
function cartesian() {
$_ = func_get_args();
if(count($_) == 0)
return array(array());
$a = array_shift($_);
$c = call_user_func_array(__FUNCTION__, $_);
$r = array();
foreach($a as $v)
foreach($c as $p)
$r[] = array_merge(array($v), $p);
return $r;
}
why is the array being buried further down in dimensions where it is not needed?
Simply because you are wrapping an array in another array when calling call_user_func.
$count = call_user_func('cartesian', array($total));
Perhaps you meant this:
$count = call_user_func('cartesian', $total);
is this the reason why my cartesain function does no longer work?
I don't know, you have not posted your cartesain, just an arrat called cartesain
EDIT as op updated the question.
If you are using PHP 5.6 you should be able to use the splat operator.
call_user_func("cartesain", ...$total);
Disclaimer, I have not tested this.
Arrays and Traversable objects can be unpacked into argument lists when calling functions by using the ... operator.

Efficiently transforming Arrays (PHP)

Edit: Thanks to #Felix Kling and #mario for pointing me towards named capture groups and PREG_SET_ORDER, I totally learned something today.
I'm curious about a better algorithm per se, though. So please just pretend that there's no preg_match() involved.
Edit 2: Abstracted question
While answering another question here, I stumbled upon the fact that my code for turning
this:
Array
(
[0] => Array (
[0] => 1
[1] => 3
)
[1] => Array (
[0] => Description text
[1] => Different Description text
)
[2] => Array (
[0] => 123.456.12
[1] => 234.567.89
)
[3] => Array (
[0] => 10.00
[1] => 10.00
)
[4] => Array (
[0] => 10.00
[1] => 30.00
)
)
into that:
Array
(
[0] => Array
(
[qty] => 1
[description] => "Description text"
[sku] => 123.456.12
[price] => 10.00
[total] => 10.00
)
…
)
is fugly:
$field_names = array('qty', 'description', 'sku', 'price', 'total');
$result_arr = array();
$num_iter = count(matches[0]);
for ($i = 0; $i < $num_iter; $i++) {
foreach ($field_names as $index => $field_name) {
$result_arr[$i][$field_name] = array_shift($input_arr[$index]);
}
}
Any suggestions for improvement?
There is one simpler way to produce the desired output.
while (count($input_arr[0])) {
$values = array_map("array_shift", & $input_arr);
$result_arr[] = array_combine($field_names, $values);
}
This won't work past PHP 5.3, as it requires forcibly passing a parameter by reference. (Avoiding any dumbing-down-the-language remarks here). But you can of course chop off the entries with a more elaborate manual loop at any time.
The real simplification for such cases is however array_combine to turn a list into an associative array.

calculations between two Multidimensional arrays

I have this code:
$id = new matrix(array(0=>array(1,0.5,3), 1=>array(2,1,4), 2=>array(1/3,1/4,1)));
$soma = $id->times($id)->sumRows();
That outputs this:
matrix Object ( [numbers] => Array ( [0] => Array ( [0] => 12.75 [1] => 22.3333333333 [2] => 4.83333333333 ) ) [numColumns] => 3 [numRows] => 1 )
and:
$total = $id->times($id)->sumRows()->sumTotal($id);
That outputs this:
matrix Object ( [numbers] => Array ( [0] => Array ( [0] => 39.9166666667 ) ) [numColumns] => 3 [numRows] => 1 )
Now, i am trying to make:
foreach ($soma as $value){
$final = (int)$value/(int)$total;
print_r ((int)$final);
}
The output will be 000.
Must be:
12.75/39.9166666667 = 0,3269230769230769
22.3333333333 / 39.9166666667 = ...
and so on
Thanks!
Just some ideas, without really knowing much about the matrix class...
All those (int)s should probably be (float)s, as you seem to want a non-int answer.
$value is itself an object, so you'll probably need to use $value['numbers'][0][0 or 1 or 2]. Same goes for $total.
the issue is solved :
documentation:
get_data($..)

Categories