This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 6 months ago.
Hah, I had no idea how else to phrase that. I'm trying to reformat a set of three arrays generated by form field inputs, into something that better matches my models, so I can save the values to the db.
Not sure if the solution should be some array manipulation or that I should change the "name" attribute in my form fields.
currently I have an array of my input data:
array(
'image_id' =>
array
0 => '454' (length=3),
1 => '455' (length=3),
2 => '456' (length=3)
'title' =>
array
0 => 'title1' (length=6),
1 => 'title2' (length=0),
2 => '' (length=6)
'caption' =>
array
0 => 'caption1' (length=8),
1 => '' (length=8),
2 => 'caption3' (length=8)
);
and would like to change it to something like, so I can iterate over and save each array of values to the corresponding resource in my db.
array(
0 =>
array
'image_id' => '454',
'title' => 'title1',
'caption' => 'caption1'
1 =>
array
'image_id' => '455',
'title' => 'title2',
'caption' => ''
2 =>
array
'image_id' => '456',
'title' => '',
'caption' => 'caption3'
);
This would iterate through the array with 2 foreach loops. They would use each other's key to construct the new array, so it would work in any case:
$data = array(
'image_id' => array(454, 455, 456),
'title' => array('title1', 'title2', ''),
'caption' => array('caption1', '', 'caption3')
);
$result = array();
foreach($data as $key => $value) {
foreach ($value as $k => $v) {
$result[$k][$key] = $v;
}
}
This'll do it:
$array = call_user_func_array('array_map', array_merge(
[function () use ($array) { return array_combine(array_keys($array), func_get_args()); }],
$array
));
Assuming though that this data is originally coming from an HTML form, you can fix the data right there already:
<input name="data[0][image_id]">
<input name="data[0][title]">
<input name="data[0][caption]">
<input name="data[1][image_id]">
<input name="data[1][title]">
<input name="data[1][caption]">
Then it will get to your server in the correct format already.
Related
I would need to combine two different fields.
In the first field I generate days of the month. I want to list all days of the month.
I would like to add a second field to them, where there are items for each day. But, for example, there are no items on weekends or on other days. Ie. that field two will always have fewer items.
The second field is tightened from the DB.
I would need to do a JOIN like in MySQL for the first field.
It occurred to me that in MySQL it would be possible to make a temporary table with a given month and link it here, but I don't think it's right.
$arrayDate = [0 => '20210401',1 => '20210402',2 => '20210403',3 => '20210404',4 => '20210405',5 => '20210406',6 => '20210407',7 => '20210408',8 => '20210409',9 => '20210410',10 => '20210411',11 => '20210412',12 => '20210413',13 => '20210414',14 => '20210415',15 => '20210416',16 => '20210417',17 => '20210418',18 => '20210419',19 => '20210420',20 => '20210421',21 => '20210422',22 => '20210423',23 => '20210424',24 => '20210425',25 => '20210426',26 => '20210427',27 => '20210428',28 => '20210429',29 => '20210430'];
$arrayItem[35] = ['id' => 35, 'date' => '20210401', 'item' => 'aaaa'];
$arrayItem[36] = ['id' => 36, 'date' => '20210402', 'item' => 'bbbb'];
$arrayItem[37] = ['id' => 36, 'date' => '20210430', 'item' => 'cccc'];
// i need output
20210401 - aaaa
20210402 - bbbb
20210403 - empty
20210404 - empty
...
20210430 - cccc
EDIT: I use nested loops, but I still can't get the right output
foreach ($arrayDate as $date) {
foreach ($arrayItem as $item) {
if ($date == $item['date']) {
bdump($item['date']);
} else {
bdump($date);
}
}
}
bdump($item['date']) = '20210401', '20210402', '20210430'
bdump($date) = '20210401', '20210401', '20210402', '20210402', '20210403', '20210403', '20210403', '20210404', '20210404', '20210404', '20210405', '20210405', '20210405' ....
With array_column you create a array from $arrayItem with date as key.
$dateItem is an array like
array (
20210401 => "aaaa",
20210402 => "bbbb",
20210430 => "cccc",
)
The output you can do with a simple foreach.
$dateItem = array_column($arrayItem,'item','date');
foreach($arrayDate as $date){
echo $date.' '.($dateItem[$date] ?? 'empty')."<br>\n";
}
Note:
With
array_column($arrayItem,null,'date')
you get a two-dimensional array with a date as a key that can be used.
array (
20210401 =>
array (
'id' => 35,
'date' => "20210401",
'item' => "aaaa",
),
20210402 =>
array (
'id' => 36,
'date' => "20210402",
'item' => "bbbb",
),
20210430 =>
array (
'id' => 36,
'date' => "20210430",
'item' => "cccc",
),
)
** I have edited this to show how I got my code to work using array_search
I have an array, $arr1 with 5 columns as such:
key id name style age whim
0 14 bob big 33 no
1 72 jill big 22 yes
2 39 sue yes 111 yes
3 994 lucy small 23 no
4 15 sis med 24 no
5 16 maj med 87 yes
6 879 Ike larg 56 no
7 286 Jed big 23 yes
This array is in a cache, not a database.
I then have a second array with a list of id values -
$arr2 = array(0=>14, 1=>72, 2=>8790)
How do I filter $arr1 so it returns only the rows with the id values in $arr2?
I got my code to work as follows:
$arr1 = new CachedStuff(); // get cache
$resultingArray = []; // create an empty array to hold rows
$filter_function = function ($row) use ($arr2) {
return (array_search($row['id'], $arr2));
};
$resultingArrayIDs = $arr1->GetIds($filter_function, $resultingArray);
This gives me two outputs: $resultingArray & $resultingArrayIDs both of which represent the intersection of the $arr1 and $arr2.
This whole task can be accomplished with just one slick, native function call -- array_uintersect().
Because the two compared parameters in the custom callback may come either input array, try to access from the id column and if there isn't one declered, then fallback to the parameter's value.
Under the hood, this function performs sorting while evaluating as a means to improve execution time / processing speed. I expect this approach to outperform iterated calls of in_array() purely from a point of minimized function calls.
Code: (Demo)
var_export(
array_uintersect(
$arr1,
$arr2,
fn($a, $b) =>
($a['id'] ?? $a)
<=>
($b['id'] ?? $b)
)
);
Something like this should do it, provided I've understood your question and data structure correctly:
$dataArray = [
[ 'key' => 0, 'id' => 14 , 'name' => 'bob' , 'style' => 'big' , 'age' => 33 , 'whim' => 'no' ],
[ 'key' => 1, 'id' => 72 , 'name' => 'jill' , 'style' => 'big' , 'age' => 22 , 'whim' => 'yes' ],
[ 'key' => 2, 'id' => 39 , 'name' => 'sue' , 'style' => 'yes' , 'age' => 111 , 'whim' => 'yes' ],
[ 'key' => 3, 'id' => 994 , 'name' => 'lucy' , 'style' => 'small' , 'age' => 23 , 'whim' => 'no' ],
[ 'key' => 4, 'id' => 15 , 'name' => 'sis' , 'style' => 'med' , 'age' => 24 , 'whim' => 'no' ],
[ 'key' => 5, 'id' => 16 , 'name' => 'maj' , 'style' => 'med' , 'age' => 87 , 'whim' => 'yes' ],
[ 'key' => 6, 'id' => 879 , 'name' => 'Ike' , 'style' => 'larg' , 'age' => 56 , 'whim' => 'no' ],
[ 'key' => 7, 'id' => 286 , 'name' => 'Jed' , 'style' => 'big' , 'age' => 23 , 'whim' => 'yes' ]
];
$filterArray = [14, 72, 879];
$resultArray = array_filter( $dataArray, function( $row ) use ( $filterArray ) {
return in_array( $row[ 'id' ], $filterArray );
} );
View this example on eval.in
However, your question appears to suggest this data might be coming from a database; is that correct? If so, perhaps it's more efficient to pre-filter the results at the database-level. Either by adding a field in the SELECT query, that represents a boolean value whether a row matched your filter ids, or by simply not returning the other rows at all.
One way is with foreach loop with array_search()
$result = [];
foreach ($arr1 as $value) { // Loop thru $arr1
if (array_search($value['id'], $arr2) !== false) { // Check if id is in $arr2
$result[] = $value; // Push to result if true
}
}
// print result
print_r($result);
As #DecentDabbler mentioned - if the data is coming out of a database, using an IN on your WHERE will allow you to retrieve only the relevant data.
Another way to filter is to use array functions
array_column extracts the value of the id column into an array
array_intersect returns the elements which are in both $arr1['id'] and $arr2
array_flip flips the resulting array such that the indices into $arr1 indicate the elements in both $arr1 and $arr2
$arr1 = [ [ 'id' => 14, 'name' => 'bob'],
['id' => 72, 'name' => 'jill'],
['id' => 39, 'name' => 'sue'],
['id' => 994, 'name' => 'lucy'],
['id' => 879, 'name'=> 'large']];
$arr2 = [ 14,72,879 ];
$intersection = array_flip(array_intersect(array_column($arr1,'id'),$arr2));
foreach ($intersection as $i) {
var_dump($arr1[$i]);;
}
I have a question. So I have this array :
$a_list_id = array(
0 => 1234
1 => 739
3 => 538
);
And this array :
$a_users = array(
0 => array(
id => 15627,
name => test
),
1 => array(
id => 1234,
name => test1
),
2 => array(
id => 739,
name => test2
)
)
The result should be :
$a_response = array(
0 => array(
id => 1234,
name => test1
)
)
Because the id 1234 is in both arrays.
I try with array_intersect but not work. Can you help me please ?
Just use loops :
$a_response = array();
foreach ($a_users as $array) {
if (in_array($array['id'], $a_list_id)) {
$a_response []= $a_users;
}
}
array_intersect will only produce useful results if the values of both arrays can be cast to the same type. You've got an array of integers and another array of arrays, they can never* match so intersect will always be empty
If you want an intersection between the arrays then you have two options:
Index the arrays so their keys are the values you want to intersect and use array_intersect_key
Implement your own array comparison logic with array_uintersect and a callback function that knows the structure of the arrays being compared
example of the former:
$a_list_id = array(
1234 => 1234
739 => 739
538 => 538
);
$a_users = array(
15627 => array(
id => 15627,
name => test
),
1234 => array(
id => 1234,
name => test1
),
739 => array(
id => 739,
name => test2
)
)
var_dump (array_intersect_key ($a_users, $a_list_id));
Example of the latter:
var_dump (array_uintersect ($a_users, $a_list_id, function ($user, $id) {
return $user ["id"] - $id; // Result should be 0 if they match, as per documentation
}))
*They can be considered the same in the case where one value is integer 0 and the other is an empty array, but that's not very useful
Try the below code using array_search() function:
$a_list_id = array(1234, 538,739);
$a_users = array(
array(
'id'=> 15627,
'name' => 'test'
),
array(
'id' => 1234,
'name' => 'test1'
),
array(
'id' => 739,
'name' => 'test2'
)
);
foreach($a_users as $a_user){
if (in_array($a_user['id'], $a_list_id)) {
$a_response[array_search($a_user['id'], $a_list_id)] = $a_user;
}
}
print_r($a_response);
Have you tried using array_intersect_uassoc? http://php.net/manual/en/function.array-intersect-uassoc.php
function compare_ids($a, $b)
{
return $a - $b['id'];
}
print_r(array_intersect_uassoc($a_list_id, $a_users, "compare_ids"));
This question already has answers here:
PHP parse/syntax errors; and how to solve them
(20 answers)
Closed 7 years ago.
Good morning, I have a little problem using sonata admin bundle, let's suppose that I have a function which returns a String, I want to pass the result of this function into as a parameter in the datagrid : something like :
protected $datagridValues = array (
'email' => array ('type1' => 2, 'value' => function()), // type 2 : >
'_page' => 1, // Display the first page (default = 1)
'_sort_by' => 'id'
);
Any one knows a way to do this ? Thank you
You can override getFilterParameters() method to change your $datagridValues:
public function getFilterParameters()
{
$this->datagridValues = array_merge(array(
'email' => array ('type1' => 2, 'value' => function()),
), $this->datagridValues);
return parent::getFilterParameters();
}
The problem is the function() in
'email' => array ('type1' => 2, 'value' => function())
Pass a correct var and it will work.
'email' => array ('type1' => 2, 'value' => 'myValue')
EDIT
To pass a function in arguments (named a callback function), you have to pass the callback name in argument, and use the call_user_func to run it then:
function mycallback(){
// do things
}
protected $datagridValues = array (
'email' => array ('type1' => 2, 'value' => 'mycallback')
'_page' => 1,
'_sort_by' => 'id'
);
Then you can do in your script :
call_user_func($datagridValues['email']['value']);
within array you cant call a function..
you can do this way.
$var = function_name();
protected $datagridValues = array (
'email' => array ('type1' => 2, 'value' => $var), // type 2 : >
'_page' => 1, // Display the first page (default = 1)
'_sort_by' => 'id'
);
i am sending an ordered json_encode list of some MySQL tables, from php, but when i retrieve it with jquery it is not in order any more? everything works fine and in order on the php side. it's the client side that i'm having trouble with. i think the problem is that i'm sending a multidimensional array from php as json. what would be the most efficient solution? also why has the order changed when retrieved by jQuery.
PHP CODE:
$user_data = array();
while($row = mysql_fetch_array($retval, MYSQL_ASSOC){
$user_id = $row['user_id'];
if(!isset($user_data[$user_id]){
$user_data[$user_id] = array(
'first_name' => $row['first_name'],
'last_name' => $row['last_name'],
'dept' => $row['dept'],
'quals' => array()
);
}
$quals = array(
'qual_cat' => $row['qual_cat'],
'qual' => $row['qual'],
'count' => $row['count']
)
$user_data[$user_id]['quals'][] = $quals;
}
echo json_encode($user_data);
jQuery:
$.post('page.php', function(post){
$.each(post, function(i,data){
alert(data.first_name+' '+data.last_name+' - '+data.dept);
});
});
PHP VAR_DUMP:
array
10 =>
array
'first_name' => string 'David' (length=5)
'last_name' => string 'Dan' (length=3)
'dept' => string 'web' (length=3)
'count' => string '5' (length=1)
'quals' =>
array
0 =>
array
...
1 =>
array
...
2 =>
array
...
3 =>
array
...
4 =>
array
...
In php, array is by default associative, so that's why you have this behavior as associative array order is not guaranteed (as per explanation in the link given by benedict_w).
To overcome this, you could try the following:
echo json_encode(array_values($user_data));
This will effectively turn your json from
["10":{prop1:val1, prop2:val2}, "25":{prop1:val1, prop2:val2}]
into
[{prop1:val1, prop2:val2}, {prop1:val1, prop2:val2}]
If you need to keep track of the id, put it inside your user_data in your php:
if(!isset($user_data[$user_id]){
$user_data[$user_id] = array(
'id' => $user_id,
'first_name' => $row['first_name'],
'last_name' => $row['last_name'],
'dept' => $row['dept'],
'quals' => array()
);
}