I have a list of product objects, it look like this:
Product Object
(
[id:private] => 1688115
[categoryId:private] => 1
[merchant:private] => theredshop
[name:private] => Pepsi Max Cans 6 x 375mL
)
every fetch data, i fetch 15 record (Im using using ElasticSearch), for the 15 record the product order is by merchant name, so it will be 1 merchant stacked on top, then goes to next merchant.
What i want to do is to 'shuffle' the object result order to at least 1 merchant shows once then put another merchant next. for example, here my current result:
merchant name
theredshop pepsi
theredshop lorem
theredshop ipsum
what i want is
merchant name
theredshop pepsi
sevel lorem
bluecircle ipsum
I know how to arrange the result by looping and checking the merchant name that has been loaded. but how can i re arrange the object result back? or should i just recreate the object?
Assuming a record table $products it can be written in PHP like that:
// restructure array as merchants having nested record sets
$merchants = [];
foreach(array_unique(array_column($products, 'merchant')) as $merchant)
$merchants[$merchant] = array_values(array_filter($products, function($v)use($merchant){ return $v->merchant === $merchant;}));
// itererate over indexes up do max. products per merchant and a add a product of
// each merchant having a record with that index
$max_count = max(array_map(function($v){return count($v);}, $merchants));
$new_order = [];
for($i = 0; $i<$max_count; $i++)
foreach ($merchants as $merchant)
if($item = $merchant[$i] ?? false)
$new_order[] = $item;
var_dump($new_order);
According to your comments you seem to have an object which you called "list" similar like that:
$products_object = (object)
[
(object)[
'merchant' => 'theredshop',
'name' => 'pepsi',
],
(object)[
'merchant' => 'sevel',
'name' => 'pepsi',
],
(object)[
'merchant' => 'sevel',
'name' => 'lorem',
],
(object)[
'merchant' => 'sevel',
'name' => 'ipsum',
],
(object)[
'merchant' => 'bluecircle',
'name' => 'ipsum',
],
];
Convert it into an array first in order to operate with array functions on it:
$products = (array) $products_object;
Related
I am trying to get away from doing things manually and repetitively by correctly utilizing loops and functions (methods) in oop programming; but I have hit a major stumbling block as it regards to multidimensional array groups, in passing the correct values to the necessary abstracted function (method) responsible for a database action.
Any help at all is very much welcomed and will enable me to move on from this stumbling block that I have been trying to push away for days upon days but without progress and it is out of true frustration and much agony that I am here begging for help.
Below is the code that for simplicity I have shortened as much as possible (can be easily tested locally by copying and pasting):
// array with table properties and form values - start
$form_fields_arr = [
'group' => [
'anime' => [ // genre
'table_prop' => [ // for update query - table properties
'table_name' => 'anime_tbl',
'account_id' => 2,
'visible' => 'yes'
],
'form_data' => [ // for update query - form values
'2' => 'Attack on Titan',
'4' => 'RWBY',
'6' => 'Rurouni Kenshin',
'8' => 'A Silent Voice'
]
],
'movie' => [ // genre
'table_prop' => [ // for update query - table properties
'table_name' => 'movie_tbl',
'account_id' => 4,
'visible' => 'yes'
],
'form_data' => [ // for update query - form values
'1' => 'Queen of Katwe',
'3' => 'Forest Gump',
'5' => 'War Horse',
'7' => 'The Fault in our Stars'
]
]
]
]; // ... end
// loop through multidimensional array and pass values to function - start
foreach ($form_fields_arr['group'] as $frm_key_1 => $frm_val_1) { // 2d array
foreach ($frm_val_1 as $frm_key_2 => $frm_val_2) { // 1d array
if (strcasecmp($frm_key_1, $frm_key_1) === 0) { // group by genre
foreach ($frm_val_2 as $frm_key_3 => $frm_val_3) { // 1d array
if (strcasecmp($frm_key_2, 'form_data') === 0) {
$title = $form_fields_arr['group'][$frm_key_1]['form_data'][$frm_key_3]; // anime/movie title
}
if (isset($frm_val_2['table_name']) &&
isset($frm_val_2['account_id']) &&
isset($frm_val_2['visible']) &&
isset($title)
) {
dbUpdate(
$frm_val_2['table_name'],
$frm_val_2['account_id'],
$frm_val_2['visible'],
$title
);
}
} // 1d array
} // if block
} // 1d array
} // 2d array
// ... end
// function that receives passed values - start
function dbUpdate($table_name, $account_id, $title_col, $form_value) {
$test_val_arr = [$table_name, $account_id, $title_col, $form_value];
return print_r($test_val_arr);
} // ... end
The above code outputs:
// array values passed to and returned from function
Array (
[0] = movie_tbl
[1] = 4
[2] = yes
[3] = A Silent Voice
)
Array (
[0] = movie_tbl
[1] = 4
[2] = yes
[3] = A Silent Voice
)
Array (
[0] = movie_tbl
[1] = 4
[2] = yes
[3] = A Silent Voice
)
Array (
[0] = movie_tbl
[1] = 4
[2] = yes
[3] = A Silent Voice
)
But the desired result that I am trying to achieve is:
// for anime genre - array values passed to and returned from function
Array (
[0] = anime_tbl
[1] = 2
[2] = yes
[3] = Attack on Titan
)
Array (
[0] = anime_tbl
[1] = 2
[2] = yes
[3] = RWBY
)
Array (
[0] = anime_tbl
[1] = 2
[2] = yes
[3] = Rurouni Kenshin
)
Array (
[0] = anime_tbl
[1] = 2
[2] = yes
[3] = A Silent Voice
)
// for movie genre - array values passed to and returned from function
Array (
[0] = movies_tbl
[1] = 4
[2] = yes
[3] = Queen of Katwe
)
Array (
[0] = movies_tbl
[1] = 4
[2] = yes
[3] = Forest Gump
)
Array (
[0] = movies_tbl
[1] = 4
[2] = yes
[3] = War Horse
)
Array (
[0] = movies_tbl
[1] = 4
[2] = yes
[3] = The Fault in our Stars
)
so upon everything royally failing with me spending literally about a week trying to fix this, telling myself that it is very simple and I really shouldn't be stuck here, out of desperation I decided to go back to my repetitive ways and tried the following:
// new array without table properties - start
$new_array = [];
$new_array['group']['anime'] = $form_fields_arr['group']['anime']['form_data'];
$new_array['group']['movie'] = $form_fields_arr['group']['movie']['form_data']; // ... end
// loop through multidimensional array and pass values to function - start
foreach ($new_array['group'] as $key_1 => $val_1) { // 2d array
foreach ($val_1 as $key_2 => $val_2) { // 1d array
if (strcasecmp($key_1, $key_1) === 0) {
dbUpdate('anime_tbl', 2, 'yes', $val_2);
dbUpdate('movie_tbl', 4, 'yes', $val_2);
} // if block
} // 1d array
} // 2d array
// ... end
But the results are still very much undesirable. Everything was working fine until I started using multidimensional arrays, simply because I realized that utilizing multidimensional arrays help me to shorten my code in other areas considerably. But I am stuck here and will have to go back further up and undo quite a lot of changes if I can't get this to work. I am pleading for help from any good soul out there. Please help me someone! Anyone!
I am being optimistic here and assuming that if by any chance I do get some help in fixing the above problem, could someone please also teach me how to loop through an array structure like the one below while yet getting the desired results without duplicates (I have truly tried but have truly failed):
// array with table properties and form values - start
$form_fields_arr = [
'table_prop' => [ // table properties group
'anime' => [ // for update query - table properties
'table_name' => 'anime_tbl',
'account_id' => 2,
'visible' => 'yes'
],
'movie' => [ // for update query - table properties
'table_name' => 'movie_tbl',
'account_id' => 4,
'visible' => 'yes'
]
],
'form_data' => [ // for update query - form values
'anime' => [ // genre
'2' => 'Attack on Titan',
'4' => 'RWBY',
'6' => 'Rurouni Kenshin',
'8' => 'A Silent Voice'
],
'movie' => [ // genre
'1' => 'Queen of Katwe',
'3' => 'Forest Gump',
'5' => 'War Horse',
'7' => 'The Fault in our Stars'
]
]
]; // ... end
You got a logic mistake in your for loops. First of all your variable namings are not very intuitive. $frm_key_1, $frm_key_2, etc. look alike and force the reader to have the array structure in mind all the time to understand the variables meaning. This led to a mistake like this one: if( strcasecmp($frm_key_1, $frm_key_1) === 0 ). This is always true.
Then you had two exclusive conditions:
if (strcasecmp($frm_key_2, 'form_data') === 0)
And:
if (isset($frm_val_2['table_name']) && /* ... */) {
If $frm_key_2 is 'form_data' you are in the second child of the genre array, yet the fields 'table_name', etc. are defined only in the first one (witht the key 'table_prop'). So both conditions can never be true at the same time.
Your condition to trigger the dbUpdate() function was, that all fields of the 'table_prop' array were present (which you iterated through at the same time), and a $title was set aswell. This was only true after your third for-loop iterated for the second time. During that iterations the $title variable got overwritten constantly, but no sbUpdate() was triggered, because $frm_val_2 had the values from 'form_data' instead of 'table_prop'. So after the 3rd for loop finished the 2nd time $title was 'A Silent Voice', which is simply the last child of the first 'form_data' array. Afterwards your 2nd for loop iterated the 2nd 'table_prop' array again, which means that now the 'dbUpdate()' condition was true, so it postet 4 times (number of childs in the 'table_prop' array) the parameters with $title = 'A Silent Voice'.
You tried to make everything as generic as possible, making everything over complicated. The best solution that works here is one that respects the specific structure.
This works:
<?php
// array with table properties and form values - start
$form_fields_arr = [
'group' => [
'anime' => [ // genre
'table_prop' => [ // for update query - table properties
'table_name' => 'anime_tbl',
'account_id' => 2,
'visible' => 'yes'
],
'form_data' => [ // for update query - form values
'2' => 'Attack on Titan',
'4' => 'RWBY',
'6' => 'Rurouni Kenshin',
'8' => 'A Silent Voice'
]
],
'movie' => [ // genre
'table_prop' => [ // for update query - table properties
'table_name' => 'movie_tbl',
'account_id' => 4,
'visible' => 'yes'
],
'form_data' => [ // for update query - form values
'1' => 'Queen of Katwe',
'3' => 'Forest Gump',
'5' => 'War Horse',
'7' => 'The Fault in our Stars'
]
]
]
];
// loop through multidimensional array and pass values to function - start
foreach ($form_fields_arr['group'] as $genreData) {
$tableProperties = $genreData['table_prop'];
if (!isset($tableProperties['table_name'])
|| !isset($tableProperties['account_id'])
|| !isset($tableProperties['visible'])) {
continue;
}
$data = $genreData['form_data'];
foreach ($data as $title) {
dbUpdate(
$tableProperties['table_name'],
$tableProperties['account_id'],
$tableProperties['visible'],
$title
);
}
}
// function that receives passed values - start
function dbUpdate($table_name, $account_id, $title_col, $form_value) {
$test_val_arr = [$table_name, $account_id, $title_col, $form_value];
return print_r($test_val_arr);
} // ... end
For the last part of the question that wasn't answered, thanks to Philipp Maurer's answer, after playing around with the code I got it to work. I am just placing the answer here for anyone who might have a similar problem and would like to better understand how to group and fetch values from a multidimensional array using a foreach loop without duplicates or incorrect results. See below code:
// array with table properties and form values - start
$form_fields_arr = [
'table_prop' => [ // table properties group
'anime' => [ // for update query - table properties
'table_name' => 'anime_tbl',
'account_id' => 2,
'visible' => 'yes'
],
'movie' => [ // for update query - table properties
'table_name' => 'movie_tbl',
'account_id' => 4,
'visible' => 'yes'
]
],
'form_data' => [ // for update query - form values
'anime' => [ // genre
'2' => 'Attack on Titan',
'4' => 'RWBY',
'6' => 'Rurouni Kenshin',
'8' => 'A Silent Voice'
],
'movie' => [ // genre
'1' => 'Queen of Katwe',
'3' => 'Forest Gump',
'5' => 'War Horse',
'7' => 'The Fault in our Stars'
]
]
]; // ... end
// loop through multidimensional array and pass values to function - start
foreach ($form_fields_arr as $index => $group_array) {
foreach ($group_array as $genre_key => $genre_val) {
if (!isset($group_array[$genre_key]['table_name']) ||
!isset($group_array[$genre_key]['account_id']) ||
!isset($group_array[$genre_key]['visible'])
) {
continue;
}
foreach ($form_fields_arr['form_data'][$genre_key] as $data_key => $data_title) {
dbUpdate(
$group_array[$genre_key]['table_name'],
$group_array[$genre_key]['account_id'],
$group_array[$genre_key]['visible'],
$data_title
);
}
}
}
// ... end
// function that receives passed values - start
function dbUpdate($table_name, $account_id, $title_col, $form_value) {
$test_val_arr = [$table_name, $account_id, $title_col, $form_value];
return print_r($test_val_arr);
} // ... end
I have a probleme with a array.
In my array that has 15,000 rows, I have columns with associated names and values (sku).
I need to show all the names and make a separate on it if the sku is equal or not to the sku that is present on my product page
Exemple : array = [ 'code' => 'name1' ,
'sku' => '123456',
'code' => 'name1',
'sku' => '456789',
'code' => 'name2',
'sku' => '4565999']
etc ..........
if sku equals sku or not in my page product, i want to show the code with distinct on this .
First you need an array of arrays structure like this:
$arr = [
[ 'code' => 'name1', 'sku' => '123456' ],
[ 'code' => 'name2', 'sku' => '456789' ],
[ 'code' => 'name3', 'sku' => '4565999' ],
.
.
.
Then you can filter your array like this:
$existing_items_on_array = array_filter($arr,
function($item) use ($existing_items_on_page){
return array_search($item["sku"], $existing_items_on_page) !== false;
});
Or better (you still need to structure an array like on first solution):
I assume your SKU's are unique. Why not make them array keys?
$item_codes = [];
foreach($arr as $item){
$item_codes[$item["sku"]] = $item["code"];
}
then you would be accessing any element's code like this:
echo $item_codes[$product["sku"]]
I have a problem to view some data in the way I want to have it.
Here is a example of the array:
$items =
0 => [
'name' => 'foo'
'description' => 'bar'
'url' => 'http://foobar.com'
'headline' => 'Headline 1'
],
1 => [
'name' => 'uni'
'description' => 'corn'
'url' => 'http://unicorn.com'
'headline' => 'Headline 1'
],
2 => [
'name' => 'awe'
'description' => 'some'
'url' => 'http://awesome.com'
'headline' => 'Headline 2'
],
And know I want to loop through the items array and want to show the headline at first and all items that have the same headline. If a item has another headline, I want to print out the other headline and the items that belongs to it.
Should look like that:
Headline 1 : <--- Items that do have this headline
name = foo
description = bar
url = http://foobar.com
name = uni
description = corn
url = http://unicorn.com
Headline 2 <----- items with a new headline
name = awe
description = some
url = http://awesome.com
I wansn't able to do that. Can someone help me there?
I've tried something like a for loop that checks the current headline with the next headline.
#for ($i = 0; $i <= count($items); $i++)
<span>{{ $items[$i]['headline'] }}</span>
#if($items[$i]['headline'] == $items[$i+1]['headline'])
.....
# else .....
#endfor
But this haven't worked well
Thanks for your help and sorry because of my bad english!
Use laravel collections with groupby() method
$collection = collect($items);
$items= $collection->groupBy('headline');
$items->toArray();
The array will be splited by headline
From Laravel Docs https://laravel.com/docs/5.4/collections#method-groupby
If your array was a collection before converting to an array, you could use groupBy() collection method:
$collection->groupBy('headline');
Maybe this could help. i am writing this code in core PHP
$arr = array();
foreach($items as $item) {
$arr[$item['headline']] = $item;
}
it will return you an array of something like
Array
(
[Headline 1] => Array
(
[name] => uni
[description] => corn
[url] => http://unicorn.com
[headline] => Headline 1
)
[Headline 2] => Array
(
[name] => awe
[description] => some
[url] => http://awesome.com
[headline] => Headline 2
)
)
First of all, I'm sorry if this is too easy for many of you... I'm learning as much as I can.
I want to create an array with customers, like:
$customers=["customer A", "customer B", "customer C"];
Then, I want to create an array with some characteristics for every customer in that array. The characteristics are 'City', 'Points' and 'Results'. Each customer has a name (string), not a number.
I would need to change (or update) a characteristic ('points') of all customers of the array when needed with PHP. Something like:
for each $customer in $customers {
$points[$customer]=$points[$customer]+2;
}
I would like to also update the info of only one customer, something like:
$points['Customer C']=$points['Customer B']+3;
Finally, I need to access the characteristics of a give Customer, like:
$i=$points['Customer A']+$result['Customer A'];
I know this is not correct, but how should I proceed in PHP?
How could I eliminate a Customer from the array $Customers (with all its characteristics)? And how could I add a new Customer to $Customers?
Thank you very much for your help. I really appreciate it.
As your question states, assoc array:
$customers = [
'customerA' => [
'points' => 100,
'city' => 'New York',
'results' => 40,
],
'customerB' => [
'points' => 75,
'city' => 'Amsterdam',
'results' => 10,
],
'customerC' => [
'points' => 25,
'city' => 'London',
'results' => 5,
],
];
// Remove customer C
unset($customers['customerC']);
// add customer D
$customers['customerD'] = [
'points' => 50,
'city' => 'Berlin',
'results' => 5,
];
// Update points of customer
$customers['customerA']['points'] += 2; // Adds 2 points
// Update points of customer by another customers points
$customers['customerB']['points'] = $customers['customerA']['points'] + 3;
// Add 2 points to each customer
foreach ($customers as $name => $properties) {
$properties['points'] += 2;
$customers[$name] = $properties;
}
The key within the customers array is the name of your customer and all the properties are within the value of that key.
You were close with your foreach:
foreach ($customers as $customer) {
$points[$customer] = $points[$customer] + 2;
}
You can update a single value like this:
$points['customer A'] = $points['customer A'] + 2;
And you can unset/remove a value like this:
unset($points['customer A']);
$customers = array();
//Adding customers
$customers["Customer 1"]["City"] = "Houston";
$customers["Customer 1"]["points"] = 3;
$customers["Customer 1"]["Results"] = "";
$customers["Customer 2"]["City"] = "Paris";
$customers["Customer 2"]["points"] = 8;
$customers["Customer 2"]["Results"] = "";
//updating characteristics
foreach ($customers as $name=>$customer)
{
$customers[$name]["City"] = "Dallas";
$customers[$name]["points"] = $customers[$name]["points"] + 2;
$customers[$name]["Results"] = "";
}
//Removing customer
unset($customers["Customer 1"]);
You can use multidimensional arrays to hold the data. This will be like how data would be returned from a database request so is a good approach to use.
// Customers array
$customers = [
[
'name' => 'Customer A',
'city' => 'Townville',
'points' => '3',
'results' => '2',
],
[
'name' => 'Customer B',
'city' => 'Blagstonberry',
'points' => '1',
'results' => '4',
],
[
'name' => 'Customer C',
'city' => 'Thorpington',
'points' => '6',
'results' => '3',
],
];
To access or edit specific customer details you will need to get the key for that customer. For example, get the key for Customer A,
$key = array_search('Customer A', array_column($customers, 'name'));
Now to access that customer's city for example, you can use the code,
$customer_a_city = $customers[$key]['city'];
To remove Customer B,
// get the key
$key = array_search('Customer B', array_column($customers, 'name'));
// remove customer
unset($customers[$key]);
Add 2 points to all customers,
foreach ($customers as &$customer) {
$customer['points'] += 2;
}
unset($customer);
Here we are passing by reference using the &. This means we can update the value directly in the foreach loop. It is good practice to unset the variable, in this case $customer so that you don't make any unwanted changes later on.
Characteristics of a particular customer - Customer C,
// get the key
$key = array_search('Customer C', array_column($customers, 'name'));
$i = $customers[$key]['points'] + $customers[$key]['results'];
Add a customer,
$customers[] = [
'name' => 'Customer D',
'city' => 'Dongleville',
'points' => '7',
'results' => '1',
];
Notes
If you search for a key for a customer by name that doesn't exist $key will be false. For example,
// get the key
$key = array_search('MADE UP NAME', array_column($customers, 'name'));
if ($key === false) {
// customer name did not exist
} else {
// do your thing
}
Also if more than one customer has the same name, the first customer key will be returned.
Reference
Passing by reference
Array search
Array column
I need to do a query and get certain kind of data. I have 2 tables, users and connections, I need to get per user how many times he/she connected per month and year.
users connections
........... ................
john 10/02/2014
john 15/02/2014
john 03/01/2015
john 06/02/2015
Is there a chance to get this info in this format:
john=>
[0]=>2014
[0]=>02
'total' =>2
[1]=>2015
[0]=>01
'total' => 1
[1]=>02
'total' => 2
[2]=>03
'total'=> 1
I'm using Codeigniter and also PHP.
Answering to #CodeGodie what I've done so far is:
public function getPeriodicity(){
$this->db->select('u.vusr_user, extract (MONTH from (to_timestamp(c.vuc_log_in))) as month, extract (YEAR from (to_timestamp(c.vuc_log_in))) as yearly, COUNT(c.vuc_log_in)');
$this->db->from('vts_users_conn c');
$this->db->join('vts_users u', 'c.vuc_vusr_id = u.vusr_id');
$this->db->group_by('u.vusr_user, month, yearly','asc');
$query = $this->db->get();
return $query->result_array();
}
Assuming you are using Codeigniter's $this->db->result_array() to obtain your database results, your initial array will look like this:
$res = array(
array(
"name" => "john",
"date" => "10/02/2014"
),
array(
"name" => "john",
"date" => "15/02/2014"
),
array(
"name" => "john",
"date" => "03/01/2015"
),
array(
"name" => "john",
"date" => "06/02/2015"
),
array(
"name" => "john",
"date" => "06/03/2015"
)
);
In order to change this array to your desired output, I would do the following:
foreach ($res as $row) {
$date_arr = explode("/", $row['date']);
$n = $row['name'];
$y = $date_arr[2];
$m = $date_arr[1];
if (!isset($final[$n]))
$final[$n] = array();
if (!isset($final[$n][$y]))
$final[$n][$y] = array();
if (!isset($final[$n][$y][$m])) {
$final[$n][$y][$m] = array("total" => 1);
} else {
$final[$n][$y][$m]["total"] = $final[$n][$y][$m]["total"] + 1;
}
}
If you var_dump your final result (var_dump($final)), you will get the following:
array (size=1)
'john' =>
array (size=2)
2014 =>
array (size=1)
'02' =>
array (size=1)
'total' => int 2
2015 =>
array (size=3)
'01' =>
array (size=1)
'total' => int 1
'02' =>
array (size=1)
'total' => int 1
'03' =>
array (size=1)
'total' => int 1
Hope this helps.
As a general rule, if you can access the data and see in your mind how you want that data to look, then it's pretty much possible to get it to do that. It's just a matter of working out the process.
In your case, I would do the following steps:
Order the data by users, then by date so everything is nicely together
Loop through the data and each time, check that the current user is the same as the last one. if it's not, create a new array key
split the date into the parts you want
check the user array for the key relating to year for that user. If the year exists, search for the month. If the month exists, add 1 to the total for that month. If the year and/or month don't exist, create the keys and set the total to be 1 for that month
Once the records have been processed, you should have the data in the format you need.