PHP Possible to move an multidimensional array element to another specific spot? - php

I am trying to figure out how I can move an array element to another spot. Is this possible?
Here is my example the var_dump array:
array
'person' =>
array
'first_name' =>
array
'...'
'last_name' =>
array
'...'
'rank' =>
array
'...'
'score' =>
array
'...'
'item' =>
array
'...'
'work' =>
array
'company' =>
array
'...'
'phone' =>
array
'...'
And of course there are values in the '...', but just to simplify it. So I need to move "score" before "rank", so the output will show score first before rank, is that possible?
Now I know the array push/pop/shift/unshift but none of those would help me here I think.
Please note, I have no control of this array...I am receiving it as is...
basically it is coming from a Wordpress plugin and it has a filter for these fields so I am using this to catch it.
add_filters( 'work_rank_fields', 'custom_order');
function custom_order($fields) {
var_dump($fields); //what you see on top
}

Using a sample array like you gave us, you could try something like this.
$sample = array(
'person' => array(
'first_name' => array('first'),
'last_name' => array('last'),
'rank' => array('rank'),
'score' => array('score'),
'item' => array('item')
),
'work' => array(
'company' => array('company'),
'phone' => array('phone')
)
);
function reorder_person( $sample )
{
extract( $sample['person'] );
// the desired order below for the keys
$sample['person'] = compact('first_name','last_name','score','rank','item');
return $sample;
}
$sample = reorder_person( $sample );
Now your var_dump of $sample should display score before rank
array(2) {
'person' =>
array(5) {
'first_name' =>
array(1) {
[0] =>
string(5) "first"
}
'last_name' =>
array(1) {
[0] =>
string(4) "last"
}
'score' =>
array(1) {
[0] =>
string(5) "score"
}
'rank' =>
array(1) {
[0] =>
string(4) "rank"
}
'item' =>
array(1) {
[0] =>
string(4) "item"
}
}
'work' =>
array(2) {
'company' =>
array(1) {
[0] =>
string(7) "company"
}
'phone' =>
array(1) {
[0] =>
string(5) "phone"
}
}
}
A little clumsy but, your wordpress filter custom_order function then might look like:
function custom_order( $fields ) {
$a = array();
foreach( $fields['person'] as $key => $value )
{
if ( $key == 'rank' ) continue; // wait until we get score first
if ( $key == 'score' )
{
$a['score'] = $value; // add score first, then rank
$a['rank'] = $fields['person']['rank'];
continue;
}
$a[$key] = $value;
}
$fields['person'] = $a;
return $fields;
}

I'm not sure which is the order criteria but I guess one of this functions can help you. Take a look particularly to last three. You just have to create the appropriate comparison function

Related

Filter array by keys and populate new multi-dimensional array from mutated keys and original values

I need to extract data from elements with keys that start with foo. from the below array:
[
'name' => 'Bar',
'location' => 'Baz',
'foo.2021-02-01' => '50000.00',
'foo.2021-03-01' => '50000.00',
'foo.2021-04-01' => '50000.00',
'foo.2021-05-01' => '',
]
After identifying qualifying keys, I need to create a new indexed array of associative rows using the date substring from the original keys like so:
[
['date' => '2021-02-01', 'value' => '50000.00'],
['date' => '2021-03-01', 'value' => '50000.00'],
['date' => '2021-04-01', 'value' => '50000.00'],
['date' => '2021-05-01', 'value' => ''],
]
I've been able to extract the keys like so:
$keys = array_keys($theData[0]);
foreach ( $keys as $key ) {
if ( preg_match( '/foo.*/', $key ) ) {
$line = explode('.', $key);
$item[]['name'] = $line[1];
}
}
but I'm losing the values.
I then tried looping through the array manually and rebuilding the desired outcome, but the keys will change so I don't know how future-proof that would be.
Is there a wildcard approach I can take to achieve this?
You almost had it:
<?php
$theData = [
'name' => 'Bar',
'location' => 'Baz',
'foo.2021-02-01' => '50000.00',
'foo.2021-03-01' => '50000.00',
'foo.2021-04-01' => '50000.00',
'foo.2021-05-01' => ''
];
$item = [];
// No need for array_keys(), foreach() can already do this
foreach( $theData as $key => $value )
{
// check if the key starts with foo.
// Regular expressions are heavy; if you'd like then substitute with:
// if ( substr( $key, 0, 4 ) === 'foo.' )
if ( preg_match( '/^foo\\./', $key ) )
{
// foo. is 4 chars long so substring from the fourth index till the end
$item[] = [
'date' => substr( $key, 4 ),
'value' => $value
];
}
}
var_dump( $item );
Output:
array(4) {
[0]=>
array(2) {
["date"]=>
string(10) "2021-02-01"
["value"]=>
string(8) "50000.00"
}
[1]=>
array(2) {
["date"]=>
string(10) "2021-03-01"
["value"]=>
string(8) "50000.00"
}
[2]=>
array(2) {
["date"]=>
string(10) "2021-04-01"
["value"]=>
string(8) "50000.00"
}
[3]=>
array(2) {
["date"]=>
string(10) "2021-05-01"
["value"]=>
string(0) ""
}
}
A simple loop, checking for the key starting with foo. and then a little code to replace foo. in the key with nothing will do the trick
If you have PHP8 or >
$arr = [
'name' => 'Bar',
'location' => 'Baz',
'foo.2021-02-01' => '50000.00',
'foo.2021-03-01' => '50000.00',
'foo.2021-04-01' => '50000.00',
'foo.2021-05-01' => ''
];
$new = [];
foreach ($arr as $k => $v){
if ( str_starts_with( $k , 'foo.' ) ) {
$new[] = ['date' => str_replace('foo.', '', $k), 'value' => $v];
}
}
print_r($new);
RESULT
Array
(
[0] => Array
([date] => 2021-02-01, [value] => 50000.00)
[1] => Array
([date] => 2021-03-01, [value] => 50000.00)
[2] => Array
([date] => 2021-04-01, [value] => 50000.00)
[3] => Array
([date] => 2021-05-01, [value] => )
)
Alternatively, for PHP versions prior to PHP8
$new = [];
foreach ($arr as $k => $v){
if ( strpos( $k , 'foo.') !== FALSE && strpos( $k , 'foo.') == 0 ) {
$new[] = ['date' => str_replace('foo.', '', $k), 'value' => $v];
}
}
Using str_starts_with and explode
$arr = [];
foreach ($theData as $k => $v){
if (str_starts_with($k, "foo."))
$arr[] = ["date" => explode(".", $k)[1], "value" => $v];
}
var_dump($arr);
sscanf() is an ideal function to call which will both check for qualifying strings and extract the desired trailing date value. It doesn't use regex, but it does require a placeholder %s to target the date substring. If a given string doesn't qualify, no element is pushed into the result array.
Code: (Demo) (without compact())
$result = [];
foreach ($array as $key => $value) {
if (sscanf($key, 'foo.%s', $date)) {
// $result[] = ['date' => $date, 'value' => $value];
$result[] = compact(['date', 'value']);
}
}
var_export($result);
If you remove the optional technique of using compact(), this solution makes fewer function calls than all other answers on this page.
I would probably only use regex if I wanted to strengthen the validation for qualifying key strings. (Demo)
$result = [];
foreach ($array as $key => $value) {
if (preg_match('~^foo\.\K\d{4}-\d{2}-\d{2}$~', $key, $m)) {
$result[] = ['date' => $m[0], 'value' => $value];
}
}
var_export($result);

PHP How to get an Array from an Array where the keys have equal Values

I'm searching for a method like array_column that, returns an array, from a column input array where the given key is the same.
sth. like this:
$records = array(
array(
'id' => 123,
'first_name' => 'John',
'last_name' => 'Doe',
),
array(
'id' => 4321,
'first_name' => 'Sally',
'last_name' => 'Smith',
),
array(
'id' => 123,
'first_name' => 'Jane',
'last_name' => 'Jones',
),
array(
'id' => 1234,
'first_name' => 'Peter',
'last_name' => 'Doe',
)
);
getFromArray($records, 'first_name', 'id'); //getFromArray(Array $input, mixed $value, mixed $key)
/* should retrun
(
[0] => John
[1] => Jane
)
*/
Thanks for every usefull help ^^
The following might help you on your way:
First - use array_filter() to find records with id's equal to '123':
$needle = '123';
$result = array_filter($records, function ($v) use ($needle) {
return $v['id'] == $needle; // when TRUE store value into result array
});
Second - use array_colum() on the result to get first_name's of hits:
$column = 'first_name';
$result = array_column($result, $column);
Output:
array(2) {
[0]=>
string(4) "John"
[1]=>
string(4) "Jane"
}
Try this:
function getFromArray($arrays, $key, $value) {
foreach($arrays as $array) {
foreach($array as $k => $v) {
if ($k == $key && $v == $value) {
return $array;
}
}
}
}
I'm assuming you are querying a database to get your ids, first names and last names. In that case, if your db is based on postgresql, then do this :
$records = pg_query($query); // this returns the 2d array you mentioned in the above question. Please use functions to manage for null.
while ($myrow = pg_fetch_array($records)) {
if ($myrow['id'] == 123) $yourow[] = $myrow['first_name'];
}
print_r($yourow);

Push array in another multidimensional array

I am trying to add values in a multidimensional array. Given below is how its supposed to be
array(
'name' => 'Hotel',
'placeholder' => 'Select the hotel',
'id' => $prefix . 'confirmation_hotel',
'type' => 'select_advanced',
'multiple' => false,
'options' => array(
'5896' => 'Hotel 1',
'6005' => 'Hotel 2'
)
),
But I getting data of options from a custom function with a foreach loop, given below is the code.
global $bookyourtravel_accommodation_helper, $bookyourtravel_car_rental_helper;
$items = $order->get_items();
$names = array();
foreach ( $items as $item_id => $item ) {
$bookyourtravel_theme_woocommerce = BookYourTravel_Theme_WooCommerce::get_instance();
$bookyourtravel_theme_woocommerce->init();
$order_names = $bookyourtravel_theme_woocommerce->order_item_name_confirmation($item);
}
$order_names output:
array(2) {
["name"]=>
string(17) "Hotel 1"
["id"]=>
string(4) "5896"
}
array(2) {
["name"]=>
string(26) "Hotel 2"
["id"]=>
string(4) "6005"
}
Now I need to add this data in the array given above. I'm not sure how to achieve this, can someone help me.
In the loop, after $order_names assignment, add :
$originalArray['options'][$order_names['id']] = $order_names['name'];
I assume your first array at the top is called $a.
So you can append an array element to your 'options' sub array like this:
foreach ($order_names as $order_name) {
array_push($a['options'], array($order_name['id'] => $order_name['name']));
}

Compare multidimensional array with each other and some array field with external variable

I have an array like below. I need to compare with each other and return the matching array on the first index and followed by other.
How can we compare whole array each other based on id and scid with $scid?
$scid = 307;
$array = array(
0 =>
array(
'id' => '485',
'scid' => 306
),
1 =>
array(
'id' => '484',
'scid' => null
),
2 =>
array(
'id' => '486',
'scid' => 305
),
3 =>
array(
'id' => '485',
'scid' => 307
),
4 =>
array(
'id' => '485',
'scid' => 309
),
5 =>
array(
'id' => '485',
'scid' => 329
),
);
The result array should be like
array(3) {
[485]=> array(2) { ["id"]=> string(3) "485" ["scid"]=> int(307) }
[484]=> array(2) { ["id"]=> string(3) "484" ["scid"]=> NULL }
[486]=> array(2) { ["id"]=> string(3) "486" ["scid"]=> int(305) }
}
If array has duplicate id on which scid is not matching then we can pick any id value.
Note :The matching sub array should always be the first index of resulting array.An amount will always be unique and might contain null as well in array.
You want something like this?
$result = [];
foreach ($array as $item) {
$result[$item['id']] = ['id' => $item['id'], 'scid' => $item['scid']];
}
var_dump($result);
Try this,
$temp = [];
foreach($array as $k => $v){
$temp[$v['id']][] = $v;
}
Give it a try, this will work.

Sorting an associative array

I have an array $array
$array =>
(
['name'] => (
"Ronaldo","Ribery","Bale","Messi"
),
['rank'] => (
2,4,1,3
)
)
Now How can i sort the array DESC using rank field along with the name
Expected output ->
$array =>
(
['name'] => (
"Ribery","Messi","Ronaldo","Bale"
),
['rank'] => (
4,3,2,1
)
)
A valid use for oft-misunderstood array_multisort()
<?php
$array = [
'name' => ["Ronaldo","Ribery","Bale","Messi"],
'rank' => [2,4,1,3]
];
array_multisort(
$array['rank'], SORT_DESC, SORT_NUMERIC,
$array['name'], SORT_ASC, SORT_STRING
);
var_dump($array);
array(2) {
'name' =>
array(4) {
[0] =>
string(6) "Ribery"
[1] =>
string(5) "Messi"
[2] =>
string(7) "Ronaldo"
[3] =>
string(4) "Bale"
}
'rank' =>
array(4) {
[0] =>
int(4)
[1] =>
int(3)
[2] =>
int(2)
[3] =>
int(1)
}
}
Check out this php article also if you want your two arrays to have a relation than you could better write it like this:
array(
array(
name => 'Messi',
rank => 4,
),
etc..
);
Why not change your data structure to be able to work with objects?
class Player {
public $name; // would be better as private and add getters
public $rank;
public function __construct($name, $rank) {
$this->name = $name;
$this->rank = $rank;
}
}
Then fill your array (I'm not familiar with soccer):
$players = [ // or array(...) if you are using older PHP
new Player('Foo', 3),
new Player('Bar', 1),
new Player('FooBar', 2)
];
Then you can use the regular sort:
// or a function name, if using older PHP
usort($players, function (Player $a, Player $b) {
if ($a->rank == $b->rank) {
return 0;
}
return ($a->rank < $b->rank) ? -1 : 1;
});

Categories