I have a PHP array that looks like this:
Array
(
[340] => Array
(
[1] => 1
[2] => 18
[3] => 23
)
[341] => Array
(
[1] => 1
[2] => 17
[3] => 23
)
[342] => Array
(
[1] => 1
[2] => 16
[3] => 23
)
[343] => Array
)
The array is actually longer and contains about 40 elements. There will be other arrays that contain a different number of child elements. The array is formatted as
productID => array (
$attributeID => attributeValueID,
$attributeID => attributeValueID,
$attributeID => attributeValueID
)
What I need is an array that shows the valid values for all other attributes. The output array might looks something like
Array
(
18 => array(
1 => array(
11, 12, 13, 14, 15
)
2 => array(
19, 20, 21, 22
)
)
19 => array(
1 => array(
11, 13, 14, 15
)
2 => array(
21, 22
)
)
The format of this array is
attributeValueID => array(
attributeID => attributeValues,
attributeID => attributeValues
)
I've been working with some recursion functions but I've only been able to get a list of every possible combination between all the values which isn't what I need. Any help would be greatly appreciated.
Clarification on what I mean by "valid" values: What the 1, 2, and 3 values represent here are color, size, and length. The ultimate goal here is to create a series of javascript arrays I'll use to update options on the page when a user selects values. For example when they select the color black I need to update the sizes and lengths on the page to reflect only sizes and lengths available in black. I can create the arrays manually but this is not a good solution.
Ok, if I get that right now, you have Products with four attributes: id, color, size and length, which you represent as
[product_id] => array (
1 => [color_id],
2 => [size_id],
3 => [length_id]
)
Personally, I find this structure somewhat clumsy. Product id should be inside the array, because it is an attribute of product. Also, using index numbers instead of the property names, makes your products difficult to understand.
Now, what you want to do is, find all possible combinations of one of the attributes, e.g. all size_id and length_id when the user selects color_id for e.g. black.
You could do that with a finder method:
function findCombinationsByColorId($color_id, $products)
{
$combos = array($color_id => array(
'sizes' => array(),
'lengths' => array(),
'products' => array()
));
foreach($products as $productId => $product)
{
if($product[1] === $color_id) {
$combos['sizes'][] = $product[2];
$combos['lengths'][] = $product[3];
$combos['products'][] = $productId;
}
}
return $combos;
}
Now, when you need to find all combinations for black and black is color_id of 0, you'd do findCombinationsByColorId(0, $productArray) and it would return an array holding all possible sizes, lengths and product Ids for this color.
You'd write additional functions for getting combinations by the other attributes. You could make the finder method generic, but I leave that up to you to figure out how.
What I dont get is why you are sorting this on the array level at all. I assume you get the possible products from somewhere, e.g. a database. So why not get the combos from there. That would probably be as easy as SELECT size_id, length_id, product_id from products where color_id = 0.
Assuming the output should actually be:
attributeValueID => array(
attributeID => productID,
attributeID => productID
)
(If not where do the attribute values come from?)
Recursion would not be needed, just something along these lines to re-jig the array:
$products = array( 340 => array(
1 => 1,
2 => 18,
3 => 23
),
341 => array(
1 => 1,
2 => 17,
3 => 23
),
342 => array(
1 => 1,
2 => 16,
3 => 23
),
343 => array()
);
$output = array();
foreach($products as $product_id=>$attributes){
$attribute_id;
foreach($attributes as $attribute_id=>$attribute_value){
$output[$attribute_value][$attribute_id][] = $product_id;
}
// optionaly filter for dup product ids
//$output[$attribute_value][$attribute_id] = array_unique($output[$attribute_value][$attribute_id], SORT_NUMERIC);
}
The answer Gordon supplied is closest to what I'm looking for but is not very efficient given the way my initial array was formatted. Though I can't recall why now, my original purpose in using arrays was to avoid having to make a new query each time someone selects an option. The easy solution is just to proceed with the queries so that's what I'll do.
Related
Array(
[User1] => 162
[User2] => 15
[User3] => 158
[User4] => 92
[User5] => 2
[User6] => 3
[User7] => 2
[User8] => 25
[User9] => 10
[User10] => 6
[User11] => 14
)
Above is my array of arrays. This list is completely dynamic - the values(numbers) change, and all of the Users are not numbers, but have actual user names - they don't say User1, they say instead like TomJohnson4512 - on and on, they're all different
All I want to do, is some sort of loop to add up and display/print/echo the values. I don't care about the user names, all I want is a sum of the values.
Any ideas?
All you need to do is use array_sum ( $array ) so assuming your array is called $array, do this
$total = array_sum ( $array );
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 looked at different options how to sort arrays. But somehow none of the given PHP commands suit my purpose.
Example - I have an array like this :
Array
(
[abc] => Array
(
[2] => 2
[3] => 3
[5] => 5
)
)
But I want to change the array to
[0] => 2
[1] => 3
[2] => 5
In other words I want to remove all keys - sort all values from LOW to HIGH and then just give em the keys from zero to X
It's much easier to work with such an array if you want to use some loops like (for, while, etc.)
Just use sort and array_values.
<?php
$array = array(
'abc' => array(
2 => 2,
5 => 5,
3 => 3,
),
);
sort($array['abc']);
$array = array_values($array['abc']);
print_r($array);
I've popped up an example at http://3v4l.org/51naW
Been working on this for 4 hours. My eyes are starting to hurt and my brain is weary from paradox.
So here is the setup. 3 arrays:
An array of posts that are advertisements
An array of normal posts
An array of taken positions which is pulled from array 1
The ad array has predefined spots.
I have merged the 2 arrays because the ads are basically integrated into the normal flow of posts. I have even been able to assign every post a spot based on the natural order of the posts, and the assigned spot for the ad. So if a post's natural spot has an ad in it, then that posts's position needs to bump forward one. This is easy if there is only 1 ad in the stream. But the thing is set up for multiple ads of arbitrary number.
So here is how I bump the position of each non-ad element in the array. I could run this again a few times I think and that should cover when there are additional ads but it seems wrong and unholy.
Wondering if anyone can solve this problem because I am sick of the taste of my own tears.
if(in_array($newarray[$key]['position'],$taken)){
$newkey = ($newarray[$key]['position'] + 1);
$newarray[$key]['position'] = $newkey;
$taken[] = $newkey;
In the end I need the merged array with all positions correctly assigned and unique.
You could write a recursive function to pull the next available position number, but if you're working with a small number of posts + ads, something like below would be quick and easy. Note that this assumes you need to preserve the original keys for the ads and posts arrays. If you don't need to do that then you can simplify it even further.
// Sample array of ads
$ads = array('ad1' => array('position' => 1),
'ad2' => array('position' => 4),
'ad3' => array('position' => 6),
'ad4' => array('position' => 10));
// Identify ad positions
foreach ( $ads as $k => $v ) {
$adPositions[$v['position']] = $v['position'];
}
// Identify available positions
$availablePositions = array_combine(range(1,100), range(1,100));
$availablePositions = array_diff_key($availablePositions, $adPositions);
// Sample posts
$posts = array('post1' => array('position' => false),
'post2' => array('position' => false),
'post3' => array('position' => false),
'post4' => array('position' => false),
'post5' => array('position' => false),
'post6' => array('position' => false));
// Use first (lowest number) available position as post position
foreach ( $posts as $k => $v ) {
$posts[$k]['position'] = array_shift($availablePositions);
}
// Merge arrays
$merged = array_merge($ads, $posts);
// Create list of positions for use with array_multisort
foreach ( $merged as $k => $v ) {
$position[$k] = $v['position'];
}
// Sort $merged by ['position']
array_multisort($position, SORT_ASC, $merged);
Gives you:
Array
(
[ad1] => Array
(
[position] => 1
)
[post1] => Array
(
[position] => 2
)
[post2] => Array
(
[position] => 3
)
[ad2] => Array
(
[position] => 4
)
[post3] => Array
(
[position] => 5
)
[ad3] => Array
(
[position] => 6
)
[post4] => Array
(
[position] => 7
)
[post5] => Array
(
[position] => 8
)
[post6] => Array
(
[position] => 9
)
[ad4] => Array
(
[position] => 10
)
)
Can anyone please help me out with that one. I'm getting the locale of Facebook page fans. The output from Facebook is in JSON format. After I json_decode($fb_output) I end up with array below. I'd like to echo a list with the top 10 languages (or all if there are less than 10) and the value in the key(number of people who speak that language). So far I've unsuccessfully tried to get it with foreach ($fb_output $key => $value)
Here is the array:
Array (
[0] => stdClass Object (
[value] => stdClass Object (
[de_DE] => 8527
[en_US] => 313
[en_GB] => 147
[tr_TR] => 106
[it_IT] => 79
[sr_RS] => 25
[hu_HU] => 24
[es_ES] => 15
[bs_BA] => 12
[es_LA] => 12
[sk_SK] => 11
[ro_RO] => 10
[ru_RU] => 9
[pt_BR] => 9
[nl_NL] => 8
[hr_HR] => 8
[fr_FR] => 7
[sv_SE] => 5
[cs_CZ] => 5
[bg_BG] => 5
)
[end_time] => 2012-03-05T08:00:00+0000 ) )
The number of keys in this array varies from user to user so it'd need to be flexible.
How about something like this:
$topTen = array_slice(array_keys( (array) $fb_output[0]->value ), 0, 10);
What it does:
Transforms the stdClass Object into an native array. ((array) operator)
Turns that array into another array, containing only its keys. (array_keys() function)
Extracts the first ten entries of that array. (array_slice() function)
If you want to extract the top ten including their values, skip the array_keys part and make sure, that the keys of the array don't get mixed up while slicing it (4th parameter of that function, see the docs for more information):
$topTen = array_slice( (array) $fb_output[0]->value, 0, 10, true);
echo $topTen['en_GB']; // 147