Related
I seem to get stuck at a (at first glance) simple thing:
I have a nested assoc array i.e.
"stock" => [
123 => [
3 => 17,
5 => 5,
7 => 0
],
456 => [
3 => 1,
5 => 3,
7 => 7
]
]
These represent stocks of items (123 and 456) in warehouses (3, 5 and 7).
Now I want to update stock in one warehouse for one item i.e.
"stock" => [
123 => [
3 => 11
]
]
I have tried to approach this via array_merge (re-keys the array) and array_merge_recursive (strangely does the same while it shouldn't - are numeric keys the reason?) but to no avail. Also I found this interesting bit https://vancelucas.com/blog/php-array_merge-preserving-numeric-keys/ but that replaces the entire branch of the array (so I'm losing warehouses 5 and 7).
Does anyone have some clever idea about this?
This should be enough:
$newArray = array_replace_recursive($sourceArray, $newDataArray);
Fiddle here https://3v4l.org/qdejB
Here is your snippet,
foreach ($temp['stock'] as $key => &$value) {
foreach ($value as $key1 => $value1) {
// no need to check, it will add at respective key matching
$arr['stock'][$key][$key1] = $value1;
}
}
working demo.
Correct me if I'm wrong, but nothing seems to be able to stop you from:
$foo['stock'][123][3] = 11;
**EDIT:
I am trying to display the number of keys in my arrays that start with a "P", "M" and "D". I think I should be using array_maps and have some luck with it but I am now stuck and tried looking through the manual, on here and w3schools with no luck.
I'm using version 5.6.36 of PHP with XAMPP on a local server. I've tried playing around with array_maps which I think is the right command to use, but I just cant get my head around how to use it properly. I've read the manual on it, looked on here, looked on youtube and W3Schools with no luck. Can anyone help please?
I have this array:
$tasks = array
(
0 => 'P1',
1 => 'M1',
2 => 'D1',
3 => 'P2',
4 => 'D2'
);
I want it to display this:
Array
(
[P] => 2
[M] => 1
[D] => 2
)
See how it returns the number of P's M's and D's nice and neatly?
From what I understand, the solution code should be something like this:
$array2 = array_map(function(???????){
return ??????????;
}, $tasks);
$array2a = (array_count_values($array2));
echo "<pre>"; print_r($array2a); echo "</pre>";
Please help?!
you can use array_map as following :
$tasks = array
(
0 => 'P1',
1 => 'M1',
2 => 'D1',
3 => 'P2',
4 => 'D2'
);
$charsToCheck = array('P','M','D');
$result = array_map(function($v) use ($charsToCheck){
if(in_array(substr( $v, 0, 1),$charsToCheck))
return substr( $v, 0, 1);
}, $tasks);
print_r(array_count_values($result));
Result:-
Array
(
[P] => 2
[M] => 1
[D] => 2
)
The function array_map() creates one output element from every input element. Since you don't want that, it is the wrong tool. Probably the easiest way to achieve your goal is to use a simple loop. However, if things get more complicated, this may not scale well. For those cases, array_reduce() could come in handy:
$input = [
0 => 'P1',
1 => 'M1',
2 => 'D1',
3 => 'P2',
4 => 'D2',
];
$frequency = array_reduce(
$input,
function ($carry, $item) {
$initial = substr($item, 0, 1);
if (array_key_exists($initial, $carry)) {
$carry[$initial] += 1;
}
return $carry;
},
[
'P' => 0,
'M' => 0,
'D' => 0,
]
);
echo json_encode($frequency, JSON_PRETTY_PRINT) . PHP_EOL;
The point of this is that it defines what to do with a single element ($item) and how to modify the resulting state ($carry) in a single function, keeping this part away from the iteration part. Since this avoids mutable state, this can also be seen as a functional (as in "functional programming") approach.
You cannot use array_map for that... You could use reduce I guess but here's a fast and easy way... Basically you create your new array and do the counting according to the first letter of your tasks array.
$list = new Array();
foreach($tasks as $task){
if($list[$task{0}]){
$list[$task{0}]++;
}else{
$list[$task{0}] = 1;
}
}
The problem you'd get with array_map is that it would always produce a 1:1 ratio of your array, which is not what you want...
(sorry for the bad PHP if it is, been ages...)
EDIT:
Using your edited question, here's your possible usage:
$array2 = array_map(function($val){
return $val{0};
}, $tasks);
The key to both answers is the $var{0} part, this extracts the character at index 0...
I'm trying to POST an array to a RESTful PHP API. The idea is to allow (n>0) records, each containing a remote_id, a dimension_id and a metric.
Here's my client Python:
data = urllib.urlencode([
("remote_id", 1),
("dimension_id", 1),
("metric",metric1),
("remote_id", 1),
("dimension_id", 2),
("metric",metric2)
])
response = urllib2.urlopen(url=url, data=data)
And here's my serverside PHP
<?php
print_r($_POST);
?>
This returns, predictably:
Array
(
[remote_id] => 1
[dimension_id] => 2
[metric] => 16
)
It looks to me like I'm overwriting every instance of remote_id, dimension_id and metric with the final values, which is unsurprising since they're all keyed with identical names.
What's the proper way to do this? I can see a horrible method with unique keys (1_remote_id, 1_dimension_id, 1_metric + 2_remote_id, 2_dimension_id, 2_metric) but that doesn't scale very well.
I guess I'm after something like this PHP, but in Python:
<?php
$observations = array();
$observations[] = [
"remote_id" => "a1",
"metric_id" => "foo",
"metric" => 1
];
$observations[] = [
"remote_id" => "a1",
"metric_id" => "bar",
"metric" => 2
];
?>
Appreciate any tips!
Sam
Don't quote me on this (I haven't done any PHP in a LOOONG time), but this may just work:
data = urllib.urlencode([
("remote_id[]", 1),
("dimension_id[]", 1),
("metric[]",metric1),
("remote_id[]", 1),
("dimension_id[]", 2),
("metric[]",metric2)
])
I would give it a try anyway.
I have the following array:
Array
(
[data.cars] => 44
[data.xp] => Array
(
[$gte] => 100
[$lte] => 500
)
[data.money] => Array
(
[$gte] => 200
[$lte] => 1000
)
)
When issuing this array to find it returns NULL.
Am I doing something wrong, I formated it according to this page, here:
http://us1.php.net/manual/en/mongo.sqltomongo.php
So basically, if I have
SELECT * FROM mytable WHERE data.cars = 44 AND data.xp >= 100 AND data.xp <= 500 AND data.money >= 200 AND data.money <= 1000
This query when run in the console gives exactly 4 results.
Here is the query:
{$and:[{"data.cars":44}, {"data.xp": {$gt:100, $lt:500}}, {"data.money": {$gt:200, $lt:1000}}]}
My array should work, but hey, it does not, please point me to what I'm doing wrong.
Thank you!
The query on MongoDB PHP should be formatted like this:
array(
'data.cars' => 44,
'data.xp' => array(
'$gt' => 100,
'$lt' => 500
),
'data.money' => array(
'$gt' => 200,
'$lt' => 1000
)
)
By doing json_encode() on two version of arrays, both at first sight seem identical, but as you will see, they are not, I discovered the "bug".
Both array's look like so:
array(
'data.cars' => 44,
'data.xp' => array(
'$gt' => 100,
'$lt' => 500
),
'data.money' => array(
'$gt' => 200,
'$lt' => 1000
)
);
One was hardcoded the other was dynamically built, but both json encoded were different, here they are:
{"data.cars":"44","data.xp":{"$gte":"100","$lte":"500"},"data.money":{"$gte":"200","$lte":"1000"}}
{"data.cars":44,"data.xp":{"$gte":100,"$lte":500},"data.money":{"$gte":200,"$lte":1000}}
The first array had the values as string, but couldn't see that on a regular print_r or a var_dump, so what I did was a force cast on the values and ... it WORKED :)
Thank you all guys for your effort and interest!
First of all it is really bad to use . or $ symbols in a keys name (and I actually thought that this is illegal ). This is because dot operator is used to access subdocuments.
So the first thing is to change that. The second thing is that you do not need $and there. So if you want to find the document, which has a = 1 and b = 2, then you do not need to do {$and : .... } all you need to do is {a : 1, b : 2}
This is primarily a PHP answer, but the methodology may in fact be language agnostic.
After running a CSV file through a simple parser, I was given a multidimensional array that resembled something akin to this:
array( 'estimated' =>
array(
array( "TITLE" => 'MAIN', "CURR_PERF" => 100, "POT_PERF" => 75 ),
array( "TITLE" => 'HEAT', "CURR_PERF" => 90, "POT_PERF" => 60 ),
array( "TITLE" => 'CO2', "CURR_PERF" => 56, "POT_PERF" => 40 ),
),
'actual' =>
array(
array( "TITLE" => 'MAIN', "CURR_PERF" => 100, "POT_PERF" => 75 ),
array( "TITLE" => 'HEAT', "CURR_PERF" => 89 , "POT_PERF" => 75),
array( "TITLE" => 'CO2', "CURR_PERF" => 40, "POT_PERF" => 20 ),
);
);
Now, horrific data structure to one side, without refactoring of the underlying parser - how would be the best way to ensure that you can access these in a specific order? Without necessarily touching the underlying parser?
If you loop through using a for()/foreach() loop you're only going to be able to read them in a linear order - increasing or decreasing down the elements. You're not necessarily going to be able to drill down and get the specific value required.
For instance, the CSV file could express the values for estimated in a different order to the values for actual; and it may be required that they are output in yet another order.
For example, here are three different orders off the top of my head:
-> MAIN HEAT CO2
-> HEAT MAIN CO2
-> CO2 HEAT MAIN
Furthermore, as is quite usual, the label names in the CSV file are not exactly user-friendly - so they need to be 'translated' (if you like) in to something more human-friendly. Naturally, without the use of lots of if() statements if preferable!
Given it's a very specific use case, but it's something I've seen before with regards to arrays being serialised - and often finding out that they are actually nested.
I've posted one possible solution, but would be happy to see others. (In the past when I've done similar I've never accepted my own answer ;)) I'm sure there must be a more elegant way than the one I've devised..!
This was the quickest (and neatest) solution I could come up with on the spot at the time, but it's not one that I take very much pride in..! It involves multiple loops, the use of several arrays and seems to be an over-engineered mechanism for doing something which should surely be pretty simplistic?
First of all I've created an associative array to use as a dictionary to look up translations for text strings found in the CSV file:
$tbl = array( "MAIN"=>"Main Costs",
"TOTAL"=>"Total Costs",
"CO2"=>"Gas expended" );
Next up, I created an array to use as an 'index' - I entered the key values here in the order I would like them to be accessed in the application:
$index = array( "MAIN", "TOTAL", "CO2" );
I then created two blank arrays and populated them with the data from the child arrays, by using a loop I was able to make them associative - allowing me to specify use the TITLE fields as keys:
$estimated = array();
$actual = array();
foreach( $bills['estimated'] as $bill ){
$estimated[ $bill['title'] ] = $bill;
}
foreach( $bills['actual'] as $bill ){
$actual[ $bill['title'] ] = $bill;
}
By doing this I could loop through them in a specific order, regardless of the order they were parsed in, like so:
for($i=0; $i<3; $i++){
$bill = $estimated[ $index[ $i ] ];
printf(" %s: %d ", $tbl[ $index[ $i ] ], $bill['CURR_PERF'] );
}
Which would output the following, in the order I specified:
// 1. Main Costs: 100
// 2. Total Costs: 90
// 3. Gas Expended: 56
Naturally, this order could easily be changed if required. It does however:
require using an array specifically to act as an index
require using two loops simply to initialise
uses a total of four extra arrays
If this array was assigned to variable $ary like:
$ary = array(
'estimated' =>
array(
array('TITLE' => 'MAIN', 'CURR_PERF' => 100, 'POT_PERF' => 75),
array('TITLE' => 'HEAT', 'CURR_PERF' => 90, 'POT_PERF' => 60),
array('TITLE' => 'CO2', 'CURR_PERF' => 56, 'POT_PERF' => 40),
),
'actual' =>
array(
array('TITLE' => 'MAIN', 'CURR_PERF' => 100, 'POT_PERF' => 75),
array( 'TITLE' => 'HEAT', 'CURR_PERF' => 89 , 'POT_PERF' => 75),
array( 'TITLE' => 'CO2', 'CURR_PERF' => 40, 'POT_PERF' => 20 ),
);
);
Your estimated array could be accessed like:
$newVar = $ary['estimated'][2]['CURR_PERF'];
$newVar would be 56. You can reassign a value as well, like:
$ary['estimated'][0]['POT_PERF'] = 300;
That first array in the estimated array used to be 75 and is now 300.
This is how you get and set specific values in a Multi-dimensional Array.
To sort the arrays, if you need to loop over and maintain their indexes, see PHP's uasort() function. This may take some work, on your part, to develop a cmp_function, but should do what you're looking for in a different way.
See,
http://www.php.net/manual/en/function.uasort.php
and
http://www.php.net/manual/en/function.usort.php ,
which explains cmp_function better.