Hopefully someone can help me :)
I have two arrays of distributor Products Info from separate datasources but with same structure. They are held in code as variables $distro1Products and $distro2Products.
Distro1:
[MZ-V7S500BW] => Array
(
[wooCode] => 13220
[price] => 74.00
[quantity] => 25
)
[...] => Array (.......)
MZ-V7S500BW - distro product code
Distro2:
[1256421] => Array
(
[wooCode] => 13220
[price] => 82.84
[quantity] => 50
)
[...] => Array (.......)
1256421- distro product code
What I want to do is to generate new array from both array results, something like this
[13220] => Array
(
[price] => 74.00
[quantity] => 25
)
I don't know if I can ask help with logic - script should pick cheapier entry (in this case - from Distro1) but it also must check if product is in stock (quantity > 0) and if both entries are out of stock, just return 0.
What I really really need right now is a way to generate new multidimensional array from existing two multidimensional arrays, also I have plans of integrating third distro, so expandability of code would be super nice :)
Thanks in advance! ♥
Is this working :
$distro1Products = [
'MZ-V7S500BW' => [
'wooCode' => 13220,
'price' => 74.00,
'quantity' => 25
]
];
$distro2Products = [
13220 => [
'price' => 74.00,
'quantity' => 25
]
];
$fusion = array_merge(...array_map(function($code, $tab) use($distro2Products) {
$wooCode = $tab['wooCode'];
return [$wooCode => $distro2Products[$wooCode]];
}, array_keys($distro1Products), $distro1Products));
?
The goal is to find how to have a link between 'wooCode' value from first array and key from second array. When you got association, you can build your array.
Related
This question already has answers here:
Get first value of an array [duplicate]
(5 answers)
PHP: How to access the first element of an array returned by a static function [duplicate]
(2 answers)
Closed 2 years ago.
Not quite sure how to word this correctly, but I am looking for some help to to move/shift array keys so that the top level array doesn't contain another array with only one item. Basically from this:
[0] => Array
(
[0] => Array
(
[_id] => 3
[title] => Award winning wedding venue
[subtitle] => Creating a website to reflect the prestige of the brand
)
)
[1] => Array
(
[0] => Array
(
[_id] => 5
[title] => Bringing storytelling to life
[subtitle] => Bringing storytelling to life
)
)
to be like this:
[0] => Array
(
[_id] => 3
[title] => Award winning wedding venue
[subtitle] => Creating a website to reflect the prestige of the brand
)
[1] => Array
(
[_id] => 5
[title] => Bringing storytelling to life
[subtitle] => Bringing storytelling to life
)
Almost just shifting the array key up one.
The original array is created using the following:
// Start with manual relation otherwise default to next/prev
foreach ($item['related'] as $id) {
$related[] = perch_collection('Projects', [
'filter' => [
[
'filter' => '_id',
'match' => 'eq',
'value' => $id,
],
// Item is enabled
[
'filter' => 'status',
'match' => 'eq',
'value' => 'enabled',
],
],
'skip-template' => true,
], true);
}
It would be best if you modify the creation of your array instead of changing it afterwards.
// Start with manual relation otherwise default to next/prev
foreach ($item['related'] as $id) {
$related[] = perch_collection('Projects', [
'filter' => [
[
'filter' => '_id',
'match' => 'eq',
'value' => $id,
],
// Item is enabled
[
'filter' => 'status',
'match' => 'eq',
'value' => 'enabled',
],
],
'skip-template' => true,
], true)[0];
}
Note the [0] at the end of the perch_collection() function call. This is essentially the same as the second part of my answer, it just occurs earlier.
With that said, if you still want to change it after the original array is made, you could just use a simple foreach loop with a reference to the original array.
foreach($array as &$arr) {
$arr = $arr[0];
}
Using & in front of $arr is a reference. This means the loop will alter the original array, so it prevents the overhead of a temporary array.
mickmackusa let me know about another solution using array_column(), which avoids the loop completely.
$array = array_column($array, 0);
The best way to fix this problem would be at the source. This looks like a Dataset received from a database, so instead of trying to manipulate the array after you received it, you could also try to generate it in the correct format. Most DALs have methods to manipulate the return type of the resultset.
However, if that is not possible and you always only have a single element nested, this loop should do the trick.
for($i = 0; $i <= count($array); $i++) {
$shifted[$i] = $array[$i][0];
}
I have a large JSON array which is the result of querying the API of an Icinga2 monitoring system.
I have used json_decode like this in my code to decode it:
$response = json_decode($array, true);
and I can see the output looks like this:
Array
(
[results] => Array
(
[0] => Array
(
[attrs] => Array
(
[__name] => HOSTNAME0
[acknowledgement] => 0
[acknowledgement_expiry] => 0
...
...
[state] => 0
[state_type] => 1
[meta] => Array
(
)
[name] => HOSTNAME0
[type] => Host
)
[1] => Array
(
[attrs] => Array
(
[__name] => HOSTNAME1
[acknowledgement] => 0
[acknowledgement_expiry] => 0
...
...
[state] => 0
[state_type] => 1
[meta] => Array
(
)
[name] => HOSTNAME1
[type] => Host
)
There are 400 Records in total and it's quite a complex structure but the only bits I am really interested in are the name and state fields.
Basically my script has a list of 150 hostnames from another source and what I want to do is for each hostname, search for it in the array and return the value of the state field for that host.
So far I've been struggling to do this without looping through the entire array for each of the 150 hostnames. There must be a more efficient way to do a lookup in the array based on a hostname and return a single value but I can't figure it out.
Given, the name field has no logical sorting inside the json result, there is no way to look at least once at each element. If they are sorted alphabetical, you could use a simple binary search, which would give you the result in O(log(n)).
The other thing is, if you have to search for multiple names, you could put them inside an name assiciated array. This way, you only have an initial overhead of O(n) building the list and each following search would return you the state on O(1).
// building the array
$states = [];
foreach ($items as $item) {
$states[$item['name']] = $item['state'];
}
looking for HOSTNAME1
$state = $states['HOSTNAME1'];
I'm hoping that I've got the source data array in the correct layout as the format was a bit confusing from the original question. But the main idea is to use array_column to extract the "attrs" and key the result by the "name" element of this array.
$response = Array(
"results" => Array(
0 => Array(
"attrs" => Array(
"__name" => "HOSTNAME0",
"acknowledgement" => 0,
"acknowledgement_expiry" => 0,
"state" => 0,
"state_type" => 1
),
"name" => "HOSTNAME0",
"type" => "Host"
),
1 => Array(
"attrs" => Array(
"__name" => "HOSTNAME1",
"acknowledgement" => 0,
"acknowledgement_expiry" => 0,
"state" => 2,
"state_type" => 1
),
"name" => "HOSTNAME1",
"type" => "Host1"
)
)
);
$extract = array_column($response["results"], "attrs", "name");
print_r($extract);
With the sample data, this gives...
Array
(
[HOSTNAME0] => Array
(
[__name] => HOSTNAME0
[acknowledgement] => 0
[acknowledgement_expiry] => 0
[state] => 0
[state_type] => 1
)
[HOSTNAME1] => Array
(
[__name] => HOSTNAME1
[acknowledgement] => 0
[acknowledgement_expiry] => 0
[state] => 2
[state_type] => 1
)
)
So to find any server by name, you'd use
echo "HOSTNAME1=".$extract["HOSTNAME1"]["state"].PHP_EOL;
If you only wanted the state field (as you asked for) and wanted to simplify the array, you can then use...
array_walk($extract, function(&$data) {$data=$data["state"];});
print_r($extract);
The array_walk() goes through the array and just copies the state field to be the entry, so the result of this is...
Array
(
[HOSTNAME0] => 0
[HOSTNAME1] => 2
)
So now you just do...
echo "HOSTNAME1=".$extract["HOSTNAME1"].PHP_EOL;
This question already has answers here:
Group multidimensional array data based on two column values and sum values of one column in each group
(5 answers)
Closed 5 months ago.
I have following array where I am trying to merge the elements which has shelf and weight value as duplicate and sum the value of piece key.
Array
(
[0] => Array
(
[shelf] => Left
[weight] => 10.000
[piece] => 1
)
[1] => Array
(
[shelf] => Right
[weight] => 04.000
[piece] => 12
)
[2] => Array
(
[shelf] => Right
[weight] => 04.000
[piece] => 4
)
[3] => Array
(
[shelf] => Right
[weight] => 07.000
[piece] => 8
)
)
Currently I am getting following desired output with help of following SQL statement by creating the temporary table with following fields shelf, weight and piece and inserting all the four values and parsing the result in PHP with following select query
SELECT shelf, weight, SUM(piece) FROM temp GROUP BY CONCAT(shelf, weight)
Array
(
[0] => Array
(
[shelf] => Left
[weight] => 10.000
[piece] => 1
)
[1] => Array
(
[shelf] => Right
[weight] => 04.000
[piece] => 16
)
[3] => Array
(
[shelf] => Right
[weight] => 07.000
[piece] => 8
)
)
However I am believe that this can be simply achieved by PHP, but can't get my head around. Can somebody please point what I might be missing ?
Note to Moderators and SO Vigilante
Please don't take it personal but before marking or even saying this is duplicate, read my question thoroughly and understand what I am trying to achieve and only then if you agree kindly explain in detail why do you think its duplicate, rather than simply arguing on base of question with similar title
I have gone through these questions, but they don't work in my scenario, as they try to merge array and sum value based on one specific element which is usually either ID, but in my case its uniqueness is judged on combination of elements (not one)
1, 2, 3
If you absolutely have to do this in PHP, then something like:
$data = array(
array(
'shelf' => 'Left',
'weight' => '10.000',
'piece' => 1,
),
array(
'shelf' => 'Right',
'weight' => '04.000',
'piece' => 12,
),
array(
'shelf' => 'Right',
'weight' => '04.000',
'piece' => 4,
),
array(
'shelf' => 'Right',
'weight' => '07.000',
'piece' => 8,
),
);
$newData = array();
$result = array_reduce(
$data,
function($newData, $value) {
$key = $value['shelf'].$value['weight'];
if (!isset($newData[$key])) {
$newData[$key] = $value;
} else {
$newData[$key]['piece'] += $value['piece'];
}
return $newData;
},
$newData
);
var_dump($result);
will work, but I really do believe that you're creating major performance problems for yourself with your whole approach to this problem
I'm trying to make a parent child like array out of a previous array of things, some are duplicates, some are not.
I have an array that spits out like so:
[0] => Array
(
[parent] => dogs
[child_cat_1] => category one
[child_cat_2] => category two
[title] => Title
[price] => 9.49
[sku] => 3558505550
[old_post_id] => 110
)
[1] => Array
(
[parent] => cats
[child_cat_1] => category one
[child_cat_2] => category six
[title] => Title
[price] => 16.49
[sku] => 2251752419
[old_post_id] => 113
)
[2] => Array
(
[parent] => cats
[child_cat_1] => category three
[child_cat_2] => category nine
[title] => Title
[price] => 59.99
[sku] => 7944100467
[old_post_id] => 114
)
[3] => Array
(
[parent] => dogs
[child_cat_1] => category one
[child_cat_2] => category two
[title] => Title
[price] => 69.99
[sku] => 85932810243
[old_post_id] => 117
)
I'm having a real hard time creating a new array based off these arrays, and turning it into an array of parents and children.
I tried doing what this post said, but I couldn't get it to work as I'm not entirely sure of what the 'parent' is going to be.
I tried doing this, but I can't figure out how to factor in child_cat_2, and also remove the duplicates. I've also read pretty much every "Building Hierarchy out of array" on Stackoverflow, but I just can't figure this one out.
foreach($new_array as $k => $v){
$array[$v['parent']] = $v['child_cat_1'];
}
Ideally, what I'm trying to accomplish is arranging each child_cat_2 under child_cat_1, and then both under parent, but then also remove the duplicates. I think the parent only has 11 types, but the two children have up to 100 each.
Can someone point me in the right direction to get these arrays sorted out.
What you've described is a 3-level nested array. The code you've posted certainly won't accomplish that. You have nodes with four properties other than your array structure, so that is what you should build in a loop. Then you place them into your structure depending on the other three properties.
$results = array();
foreach ($data as $datum){
$node = array(
'title' => $datum['title']
'price' => $datum['price']
'sku' => $datum['sku']
'old_post_id' => $datum['old_post_id']
);
if (!is_array($results[$datum['parent']])) {
$results[$datum['parent']] = array();
}
if (!is_array($results[$datum['parent']][$datum['child_cat_1']])) {
$results[$datum['parent']]
[$datum['child_cat_1']] = array();
}
if (!is_array($results[$datum['parent']][$datum['child_cat_1']][$datum['child_cat_2']])) {
$results[$datum['parent']]
[$datum['child_cat_1']]
[$datum['child_cat_2']] = array();
}
$results[$datum['parent']]
[$datum['child_cat_1']]
[$datum['child_cat_2']][] = $node;
}
Is there a way to format the $this->find('all') array into the $this->find('list') in the view? The reason I ask is so that I can pass that new array into the form helper options and then use the $this->find('all') array to build some additional things I need?
Array (
[0] => Array ( [School] => Array ( [id] => 0 [name] => Nature [address] => 112 Main [max_students] => 25 [application_level] => 5 ) )
[1] => Array ( [School] => Array ( [id] => 1 [name] => Math [address] => 112 Smith [max_students] => 25 [application_level] => 0 ) )
[2] => Array ( [School] => Array ( [id] => 2 [name] => Art [address] => 112 Lane [max_students] => 25 [application_level] => 0 ) )
)
So this is the array I get when I do a find('all'). I want to build the array so it looks like:
Array (
[0] => 'Nature'
[1] => 'Math'
[2] => 'Art'
)
This is usually done by the $this->find('list') function. Though the reason I want the whole array is because I need to add the application_level into $this->Form->input() function. This is because I need to add the option of class with the application level attached so I show only the shows with the application level based on the previous selection.
EDIT: Can't I just do $this->find('list', [insert parameters here?]);? I just don't understand how you set up the additional parameters?
If your query isn't overly complicated and isn't going to return a excessive number of results, just run it twice (once for find all and once for find list).
Find all, list, first, whatever are all the same in terms of the paramaters you pass in. E.g.:
$this->Model->find('all', array(
'conditions' => array(
'field' => 500,
'status' => 'Confirmed'
),
'order' => 'id ASC'
));
... you literally replace all with list. In your case, probably easiest to do it twice, once for each. Like this:
$parameters = array(
'conditions' => array(
'field' => 500,
'status' => 'Confirmed'
),
'order' => 'id ASC'
);
$alldata = $this->Model->find('all', $parameters);
$listdata = $this->Model->find('list', $parameters);
Otherwise, you can loop through it and populate your own list:
$list = array();
foreach($findall as $row) {
$id = $row['id'];
$name = $row['name'];
$list[$id] = $name;
}
$this->set('listdata', $list);
Short answer to your question is that there's no quick, easy way to select all and list from the same query, but you can re use your parameters (conditions, order etc) by passing them in as predefined arrays, or populate your own list.
An alternative answer to creating the results formatted like find('list') from results from find('all') using CakePHP's hash utility:
//where $data is the result of find all
App::uses('Hash', 'Utility');
$ids = Hash::format($data, array('{n}.Model.id'), '{0}'); //ids in an array.
$names = Hash::format($data, array('{n}.Model.name'), '{0}'); //names in an array
$dataAsList = array_combine($ids, $names);
To improve on kai's answer. The Hash class has a method called combine that can do what you're trying to do in only one line
$list = Hash::combine($data,'{n}.Model.id','{n}.Model.name');
the $list will be a flat array like data from find('list');