I have variable products which have two attributes: size and color. When some product has attributes M->red, XL->blue, M->yellow. Below snippet show atrributess M L M and it's ok but I can't find solution how remove duplicate items
add_action('woocommerce_before_shop_loop_item_title', 'variations_loop');
function variations_loop() {
global $product;
if($product->get_type() == 'variable') {
foreach($product->get_available_variations() as $key) {
$variation = wc_get_product($key['variation_id']);
echo $variation -> attributes['pa_size'];
}
}
}
Based on your comments, it sounds like you have the following array:
[
[
"pa_size" => "m",
"pa_color" => "blue"
],
[
"pa_size" => "xl",
"pa_color" => "yellow"
],
[
"pa_size" => "m",
"pa_color" => "blue"
]
]
What you will need to do is call array_map (documentation) to get just the sizes and array_unique (documentation) to get the unique values.
Once you get those unique values, you can optionally get the products by the size by using array_filter (documentation).
Here is an example:
// define the products
$products = [
[
"pa_size" => "m",
"pa_color" => "blue"
],
[
"pa_size" => "xl",
"pa_color" => "yellow"
],
[
"pa_size" => "m",
"pa_color" => "blue"
]
];
// get just the "pa_size" values
$productSizes = array_map(function($key, $value) {
return $value["pa_size"];
}, array_keys($products), array_values($products));
// get the unique "pa_size" values
$uniqueProductSizes = array_unique($productSizes);
// loop over the unique "pa_size" values
foreach ($uniqueProductSizes as $key => $value) {
// get every product by the "pa_size"
$productsBySize = array_filter($products, function($innerKey) use ($value) {
return $value === $innerKey["pa_size"];
});
}
Fiddle: https://onlinephp.io/c/d637f
Related
This is $multidimensional data result :
[
{
"2018-11-02": [
"2"
]
},
{
"2018-11-02": [
"8",
"3"
]
}
{
"2018-11-21": [
"11",
"35",
"94",
"98",
"163"
]
},
]
$filter = [3,98,11]
How to remove object and value in $multidimensional where value not exist in $filter and after unset, the result will be turned into an object like the one below :
{
"3": 2018-11-02,
"98": 2018-11-21,
"11" : 2018-11-21
}
In my case, I am using unserialize :
for($w=0;$w<count($multidimensional);$w++) {
$hasilId2[] = (object) [
$multidimensional[$w]->date=> unserialize($multidimensional[$w]->invoiceid)
];
}
I've already try using loop :
foreach($multidimensional as $key => $value) {
if(!in_array($key, $filter)) {
unset($multidimensional[$key]);
}
}
You need a loop for the main array and a loop for the internal arrays
So it is better to put 2 loop inside each other
There is also no need to uset
You can put the correct results in a separate variable and then use it
You wanted the key to that array to be the final array value
So I used the key function to get the array key and gave the new value like this:
$result[array value] = [array key];
And finally I printed the new array:
$multidimensional = [
[
"2018-11-02" => [
"2"
]
],
[
"2018-11-02" => [
"8",
"3"
]
],
[
"2018-11-21" => [
"11",
"35",
"94",
"98",
"163"
]
],
];
$filter = [3, 98, 11];
$result = [];
foreach ($multidimensional as $val1) {
foreach (array_values($val1)[0] as $key => $val2) {
if (in_array($val2, $filter)) {
$result[$val2] = key($val1);
}
}
}
print_r($result);
Result:
Array
(
[3] => 2018-11-02
[11] => 2018-11-21
[98] => 2018-11-21
)
I'm working with an inventory database (yes, I know that this could potentially be done using mysql), but I currently end up with a PHP array.
$products = [
["id" => "123", "sku" => "MED_BL_DRESS", "size" => "medium", "color" => "black"],
["id" => "321", "sku" => "LG_GR_DRESS", "size" => "large", "color" => "green"],
["id" => "31321", "sku" => "LG_RD_DRESS", "size" => "large", "color" => "red"]
]
The user will select a size, and I want to pass into the function:
filterArray($products, ["size"=>"medium"])
and I'm hoping that I can get an array back, with only records which matched that criteria... the kicker is if I pass multiple criteria,
filterArray($products, ["size"=>"medium", "color"=>"black"])
then the array would give me back a products array with just that one product matching in the array. I'm trying to build this so that I can have any number of key values in the products array (perhaps some products have "gender" as a filter, whereas others won't). It could have many, many filter variants.
I tried looping over the array and brute forcing it, but I think there must be a more elegant way then a bunch of nested recursive functions.
Why do think it is so hard?
No recursion needed.
This answer assumes you want all results to match by AND logic. You also could extend the filter function to make use of a second array for OR logic. In ElasticSearch there is a terminology of MUST and SHOULD.
The first will find all sizes 'large'
(two results)
The second will find all sizes 'large' and color 'green'
(one result)
Filter Explanation
A key counter is used to know how many keys of the product must match
The outer loop will go through all products
For each iteration the match counter is reset to 0
Then compare how many matches are in the filter against the current product
When the matches equal the keycount, then all filters passed positive and add the product to the results.
$products = [
["id" => "123", "sku" => "MED_BL_DRESS", "size" => "medium", "color" => "black"],
["id" => "321", "sku" => "LG_GR_DRESS", "size" => "large", "color" => "green"],
["id" => "31321", "sku" => "LG_RD_DRESS", "size" => "large", "color" => "red"]
];
print_r(filterArray($products, ['size' => 'large']));
print_r(filterArray($products, ['size' => 'large', 'color' => 'green']));
function filterArray(array $products, array $filter = []): array
{
$result = [];
$keyCount = count($filter);
foreach ($products as $product) {
$match = 0;
foreach ($filter as $key => $value)
if ($product[$key] === $value) $match++;
if ($match === $keyCount) $result[] = $product;
}
return $result;
}
You could use array_filter for that. Additionally, you could pass an extra param to indicate if the row must match all the filters or if it can match any filter to make the function more dynamic and useful:
Working example
/**
* #param array $products
* #param array $filters
* #param bool $matchAll
* #return array
*/
function filterArray(array $products, array $filters, bool $matchAll = true): array
{
return array_filter($products, static function($product) use ($filters, $matchAll) {
$matches = 0;
$filterCount = count($filters);
foreach ($filters as $filterColumn => $filterValue) {
if (isset($product[$filterColumn]) && $product[$filterColumn] === $filterValue) {
$matches++;
if (!$matchAll) {
break;
}
}
}
return ($matches && !$matchAll) || ($matchAll && ($matches === $filterCount));
});
}
$products = [
["id"=>"123", "sku"=>"MED_BL_DRESS", "size"=>"medium", "color"=>"black"],
["id"=>"321", "sku"=>"LG_GR_DRESS", "size"=>"large", "color"=>"green"],
["id"=>"31321", "sku"=>"LG_RD_DRESS", "size"=>"large", "color"=>"red"]
];
// Filter matching all filters
$filters = ["size"=>"medium", "color"=>"black"];
$filteredProducts = filterArray($products, $filters);
var_dump($filteredProducts);
// Filter matching any of the filters
$filters = ["size"=>"medium", "color"=>"black", "sku"=>"LG_RD_DRESS"];
$filteredProducts = filterArray($products, $filters, false);
var_dump($filteredProducts);
This solution uses the array_filter() function. In the callback function, array_intersect_assoc() is used to check whether all elements of the $ filter array are present in the line.
function filterArray(array $products, array $filter = []): array
{
return array_filter(
$products,
function($row) use($filter){
return array_intersect_assoc($filter, $row) === $filter;
}
);
}
No matter how many qualifying associative elements you have, check the $mustHave whitelist array against each row of the $product array with !array_diff_assoc() for maximum functional-style elegance.
Code: (Demo)
$products = [
["id" => "123", "sku" => "MED_BL_DRESS", "size" => "medium", "color" => "black"],
["id" => "321", "sku" => "LG_GR_DRESS", "size" => "large", "color" => "green"],
["id" => "31321", "sku" => "LG_RD_DRESS", "size" => "large", "color" => "red"]
];
$mustHave = ['size' => 'large', 'color' => 'green'];
var_export(
array_filter(
$products,
fn($row) => !array_diff_assoc($mustHave, $row)
)
);
Hi I am new to php and I faced some problem when I need sum up array in foreach.
I had array like this:
$arrays = [
[
'orderid' => "1",
'price' => "100"
'rate' => "1"
],
[
'orderid' => "2",
'price' => "200"
'rate' => "5"
],
];
What I face when I using foreach, the price * rate will sum continuously but not sum up separately.
$bonus = array();
foreach($arrays as $data){
$bonus = $data['originalPrice'] * $data['rate'];
}
I also tried using array_map() but also cannot get my answer;
WHat I need about :
$array = [
[
'total' => 100;
],
[
'total' => 1000;
]
]
Any idea for help?
UPDATED: ALL THE ANSWER ARE CORRECTED, is the api data give me wrong info lol.
foreach($arrays as $data){
$bonus[]['total'] = $data['price'] * $data['rate'];
}
print_r($bonus);
You are using price so use that property and you need to push the value in the result array. Thus, you need to do:
<?php
$arrays=array(
array(
'orderid' => "1",
'price' => "100",
'rate' => "1"
),
array(
'orderid' => "2",
'price' => "200",
'rate' => "5"
)
);
$bonus = array();
foreach($arrays as $data){
array_push($bonus,$data['price'] * $data['rate']);
}
print_r($bonus);
?>
You can test this code at http://www.writephponline.com/
Foreach is fine, but you need to add to the bonus array rather than override with the result:
$bonus = array();
foreach($arrays as $data){
$bonus[] = array('total' => $data['originalPrice'] * $data['rate']);
}
This is adding arrays to the bonus array.
Reads all the prefix value in an array. If slug value is modules the result would be api/v1/tenants/modules/{id}, in contrast if slug value fetch the result would be api/v1/tenants/fetch/{id}.
"slug" => "api",
"children" => [
"prefix" => "v1",
"slug" => "v1",
"children" => [
"prefix" => "tenants",
"slug" => "tenants",
"children" => [
[
"prefix" => "fetch/{id}",
"slug" => "fetch",
],
[
"prefix" => "modules/{id}",
"slug" => "modules",
]
],
],
],
You can use array_walk_recursive to traverse array recursively,
$res = [];
// & so that it keeps data of $res in every loop
array_walk_recursive($arr, function ($item, $key) use (&$res) {
if ($key == 'prefix') {
$res[] = $item; // fetching only prefix values recursively
}
});
// this is your generated url
echo implode("/", $res);
Demo.
Output:
api/v1/tenants/modules/{id}
I use array-walk-recursive as:
function getPrefix($v, $k) { global $ps; if ($k == "prefix") $ps[] = $v; }
array_walk_recursive($arr, 'getPrefix');
Now, $ps is array of the prefix. Then you can use implode to add the /
Live example: 3v4l
I have the following array:
$arr = [
"elem-1" => [ "title" => "1", "desc" = > "" ],
"elem-2" => [ "title" => "2", "desc" = > "" ],
"elem-3" => [ "title" => "3", "desc" = > "" ],
"elem-4" => [ "title" => "4", "desc" = > "" ],
]
First I need to change the value from [ "title" => "1", "desc" = > "" ] to 1 (title's value).
I did this using array_walk:
array_walk($arr, function(&$value, $key) {
$value = $value["title"];
});
This will replace my value correctly. Our current array now is:
$arr = [
"elem-1" => "1",
"elem-2" => "2",
"elem-3" => "3",
"elem-4" => "4",
]
Now, I need to transform each element of this array into its own subarray. I have no idea on how to do this without a for loop. This is the desired result:
$arr = [
[ "elem-1" => "1" ],
[ "elem-2" => "2" ],
[ "elem-3" => "3" ],
[ "elem-4" => "4" ],
]
You can change your array_walk callback to produce that array.
array_walk($arr, function(&$value, $key) {
$value = [$key => $value["title"]];
});
Run the transformed array through array_values if you need to get rid of the string keys.
$arr = array_values($arr);
To offer an alternative solution you could achieve all of this with array_map
<?php
$arr = [
"elem-1" => [ "title" => "1", "desc" => "" ],
"elem-2" => [ "title" => "2", "desc" => "" ],
"elem-3" => [ "title" => "3", "desc" => "" ],
"elem-4" => [ "title" => "4", "desc" => "" ],
];
function convertToArray($key,$elem){
return [$key => $elem['title']];
}
$arr = array_map("convertToArray", array_keys($arr), $arr);
echo '<pre>';
print_r($arr);
echo '</pre>';
?>
outputs
Array
(
[0] => Array
(
[elem-1] => 1
)
[1] => Array
(
[elem-2] => 2
)
[2] => Array
(
[elem-3] => 3
)
[3] => Array
(
[elem-4] => 4
)
)
It doesn't make much sense to use array_walk() and modify by reference because the final result needs to have completely new keys on both levels. In other words, the output structure is completely different from the input and there are no salvageable/mutable parts. Mopping up the modified array with array_values() only adds to the time complexity cost.
array_map() has to bear a cost to time complexity too because array_keys() must be passed in as an additional parameter.
If you want to use array_walk(), use use() to modify the result array. This will allow you to enjoy the lowest possible time complexity.
More concise than array_walk() and cleaner to read, I would probably use a classic foreach() in my own project.
Codes: (Demo)
$result = [];
array_walk(
$arr,
function($row, $key) use(&$result) {
$result[] = [$key => $row['title']];
}
);
Or:
$result = [];
foreach ($arr as $key => $row) {
$result[] = [$key => $row['title']];
}
var_export($result);
You need to use array_map like
$new_arr= array_map(function($key,$val){
return [$key => $val['title']];},array_keys($arr),$arr);