I have four elements of data stored in variables.
I wish to create a multi-dimensional array.
Firstly, I wish the ID to be the main key for the array. And within the ID key, I wish to store description, image_med and image_full
I have started by initialising an array and pushing the ID:
$image_id = $image['id'];
$this_image = array();
array_push($this_image, $image_id);
The result is:
array(1) {
[0]=>
int(2161)
}
Now I wish to push three more elements into this ID array. I'd like to create something like the following:
array(1) {
['ID']=>
int(2161)
array(3){
['description'] => string(Description goes here),
['medium'] => string(http://www.blah.com/12345),
['full'] => string(http://www.blah.com/67890)
}
}
So first of all the parent key is called ID not just [0]
And secondly that the following three variables are added with their keys:
description ($image_desc is the variable)
medium ($image_med is the variable)
full ($image_full is the variable)
How would I do this?
Let $id be the id of the image:
$array=array();
//then you can use this code in a loop:
$array[$id]=array(
'description'=>$image_desc,
'medium'=>$image_med,
'full'=> image_full
);
There is no need to use array_push function, actually array_push has a little worse performance because of function call's overhead (this is an advanced topic, anyway)
is that what you are looking for ?
$images = array(); // an array of all images
$image_id = $image['id'];
$images[$image_id] = array(
'ID' => $image_id, // optional, would be repeating id you already have
'description' => "Blabla",
'medium' => "Blabla",
'full' => "Blabla",
);
You would do that automatically in a loop I suppose thought... And if you dont need the ID as "key", what about:
$images = array();
$image1 = array(
'ID' => $image_id,
'description' => "Blabla",
'medium' => "Blabla",
'full' => "Blabla",
);
array_push($images, $image1);
Not sure what you are looking to achieve though.
Your question is not very clear. What you probably need could be something like this:
// Create a list (of images)
$listImages = array();
// Information about an image (it can be constructed as displayed here,
// retrieved from a database or from other source)
$image = array(
'id' => 123,
'description' => 'Nice kitty',
'medium' => 'http://www.blah.com/12345',
'full' => 'http://www.blah.com/67890',
);
// Extract the ID of the image into a variable (this is for code clarity)
$imageId = $image['id'];
// Store the image in the list, indexed by image ID
$listImages[$imageId] = $image;
// Get/create another image...
$image = array(
'id' => 456,
'description' => 'another kitty',
// ... other fields here
);
// ... put it into the list (skip the helper variable $imageId)
$listImages[$image['id']] = $image;
This is how the output of print_r($listImages) looks like:
Array
(
[123] => Array
(
[id] => 123
[description] => Nice kitty
[medium] => http://www.blah.com/12345
[full] => http://www.blah.com/67890
)
[456] => Array
(
[id] => 456
[description] => another kitty
)
)
Related
I am writing a page that pulls images and image data out of a multidimensional array. I need to be able to click a button that calls a function to sort out the images by tags(IE tag_GlassDoor & tag_GlassWall) - basically to show only images that do or do not have that particular element (in this case im using 0 and 1 for yes and no), such as a glass door. I can currently make that array display the data, but I cant figure out how to sort the data by one of the array keys, or even really the syntax to pull a single value out at will.
$arrImages[] =
[
'img_sm'=>'image1.jpg',
'tag_GlassDoor'=>0,
'tag_GlassWall'=>1,
];
$arrImages[] =
[
'img_sm'=>'image2.jpg',
'tag_GlassDoor'=>1,
'tag_GlassWall'=>1,
];
Filtering is the answer, it can be used to filter one dimensional Arrays and multidimensional arrays.
the general implementation would be something like this:
$arr = array(
array(
'image' => "data",
'hasObject' => 1
),
array(
'image' => "data",
'hasObject' => 0
),
);
$finteredArray = array_filter($arr, function ($r) {
return (bool) $r['hasObject'];
});
print_r($finteredArray);
// it outputs:
// Array ( [0] => Array ( [image] => data [hasObject] => 1 ) )
I'm using Codeigniter 3 and the table library in order to display some data in the following format;
+---------------+---------------------+
| id | 102 |
+---------------+---------------------+
| First Name | Ross |
+---------------+---------------------+
| Last Name | Bing |
+---------------+---------------------+
| Title | Doctor |
+---------------+---------------------+
| Timestamp | 2019-01-18 10:17:05 |
+---------------+---------------------+
| Member Number | |
+---------------+---------------------+
A vardump of $tableData is;
Array
(
[0] => Array
(
[id] => 102
[firstname] => Ross
[lastname] => Bing
[title] => Doctor
[timestamp] => 2019-01-18 10:17:05
[member_no] =>
)
)
The PHP code I use to generate the HTML table is;
$tableData = $this->My_model->getData();
$heading = array(
'id' => 'ID',
'firstname' => 'First Name',
'lastname' => 'Last Name',
'title' => 'Title',
'timestamp' => 'Date Submitted',
'member_no' => 'Member Number'
);
$fields = array_keys($tableData[0]);
$rows = array();
foreach($fields as $key => $field) {
$rows[$key][0] = array(
'data' => '<strong>' . $heading[$field] . '</strong>'
);
foreach($tableData as $key2 => $item) {
$rows[$key][$key2 + 1] = $item[$field];
}
}
foreach($rows as $row) {
$this->table->add_row($row);
}
The above code works fine, however if a row is empty (see member_no above) i'd like to do one of two things (whichever is easiest);
hide the table row completely
display not available in the table cell
How can I achieve this?
I would do something like this:
$tableData = array (
0 =>
array (
'id' => 102,
'lastname' => 'Bing',
'title' => 'Doctor',
'timestamp' => '2019-01-1810:17:05',
'member_no' => null,
'firstname' => 'Ross', //intentionally moved to show ordering
'foobar' => 'blah' //added for example, this will be removed by array_intersect_key
),
);
$heading = array(
'id' => '<strong>ID</strong>',
'firstname' => '<strong>First Name</strong>',
'lastname' => '<strong>Last Name</strong>',
'title' => '<strong>Title</strong>',
'timestamp' => '<strong>Date Submitted</strong>',
'member_no' => '<strong>Member Number</strong>'
);
//create a default array
//this takes the keys from $heading, and makes an array with all the values as 'not available'
// ['id' => 'not available','lastname' => 'not available', ... ]
$default = array_fill_keys(array_keys($heading), 'not available');
$rows = [];
foreach($tableData as $key => $row) {
//remove all elements with strlen of 0 (in this case 'member_no')
$row = array_filter($row, function($item){return strlen($item);});
//removes 'foobar' or anything that has a key not in $heading
$row = array_intersect_key($row, $heading);
//combine $default and $data (empty items in $row are filled in from default)
//such as items removed by array_filter above
//the key order will match $default, which matches $headings
$row = array_merge($default, $row);
$rows[] = $row;
}
foreach($heading as $key=>$value) {
print_r(array_merge([['data'=>$value]], array_column($rows, $key)));
}
Output
Array
(
[0] => Array
(
[data] => <strong>ID</strong>
)
[1] => 102
//[2] => 108
//...
)
....
Sandbox
I kept these separate so it would be a bit easier to read, but there is no reason you cannot do it this way.
//...
$default = array_fill_keys(array_keys($heading), 'not available');
foreach($tableData as $key => $row) $rows[] = array_merge($default, array_intersect_key(array_filter($row, function($item){return strlen($item);}), $heading));
foreach($heading as $key=>$value) print_r(array_merge([['data'=>$value]],array_column($rows, $key)));
Sandbox
I had to guess a bit on what the end result was, so I ran your original code and it gave me this:
Array
(
[0] => Array
(
[data] => <strong>ID</strong>
)
[1] => 102
//[2] => 108
//...
)
....
In my code you can replace the print_r with this call $this->table->add_row([..array data..]);. Where array data is the stuff in the print_r call. You could make this a variable, but what's the point if its only used here. That eliminates a few of those loops (see below) and A few other advantages:
key order of $headings is preserved, elements appear where they do in the $headings array, regardless of where they are in $tableData. This allows easy re-ording of the data, too, for example: you could even map this to a dynamic array, I do this in CSV files, which allows users to change the order of the headers and columns. They can even rename the headers, because the way the key => value pairing works my_key => their_key...
Data missing from $tableData is defaulted to not available pulled in from $default, in theory you could map this manually to different things. For example: you could default timestamp to the current time by doing $default['timestamp'] = date('Y-m-d H:i:s'); right after creating it with array_fill_keys.
Extra data in $tableData not defined in $headings is removed. Which is good for forward compatibility.
And it's A bit easier to make sense of (once you know how it works) because there are less "transient" variables and less fiddling with the keys ect...
Basically what I am doing is giving control over to the $headings array, in your original code. You do this somewhat by looping over the keys (fields), but this complicates things later like this $rows[$key][$key2 + 1]. It leaves you open to undefined array index issues, if the data changes at a later time, such as adding a new field to the DB.
The order of the output is dependent on the data in $tableData which is less intuitive (and less useful) then if it depends on $headings.
Here is an example of these issues with the original code:
//for example if your data changes to this and run your original code
$tableData = array (
0 =>
array (
'id' => 102,
'lastname' => 'Bing',
'title' => 'Doctor',
'timestamp' => '2019-01-1810:17:05',
'member_no' => null,
'firstname' => 'Ross', //intentionally moved to show ordering
'foo' => 'bar' //added this undefined in $headings
),
);
You'll get this notice and also find the last 2 elements are:
<br />
<b>Notice</b>: Undefined index: foo in <b>[...][...]</b> on line <b>30</b><br />
//... all other elements ...
//in orignal: displayed in the order of $tableData
//in my code: order is based on $headings, so this would be moved to the correct location
Array(
[0] => Array (
[data] => <strong>First Name</strong>
)
[1] => Ross
)
//in orignal: $headings['foo'] is not defined so we have no label here
//in my code: this element is removed and doesn't get rendered
Array(
[0] => Array(
[data] => <strong></strong>
)
[1] => bar
)
Sandbox (Orignal Code)
While these things may never cause an issue, it highlights my point about basing the output off of $headings and not $tableData. Things tend to change, and this way if you add/remove a field from this data, you wont have to worry about it breaking this page etc...
The combination of array_fill_keys, array_intersect_key and array_merge can be used to map the headers (As I shown above) of one array to another. You can use array_combine($headings, $row) to physically swap them and you would get something like this:
[
[
'<strong>ID</strong>' => 102,
'<strong>First Name</strong>' => 'Ross',
//...
],
[...]
]
It works great for CSV files (which is what I figured it out on) and anything else you need to remap the keys for.
Anyway, hope it helps you!
I want to remove an item from an array. I can write this:
$item = array(
'id' => 1
'name' => 'name'
);
$item2 = $item;
unset($item2['id']);
$names[] = $item2;
but the last 3 lines are somewhat "cumbersome", soo un elegant. Can it be solved without creating $item2 ? Something like:
$item = array(
'id' => 1
'name' => 'name'
);
$names[] = array_ignore_index('id', $item);
From your codes, I can see that you are trying to get the names[] from item array. One possible simple solution for this specific scenario:
For example IF you have :
$items = array(
array(
//this is your item 1
'id' => 1,
'name' => 'name1'
),
array(
//this is item 2
'id' => 2,
'name' => 'name2'
)
);
and you want to retrieve the names in the names array.
You can just do:
$names = array_column($items, 'name');
It will return:
Array
(
[0] => "name1"
[1] => "name2"
)
Please note this solution is best fit for this specific scenario, it may not fit your current scenario depending.
The shortest out of the box solution is to create a diff of the array keys:
$names[] = array_diff_key($item, array_flip(['id']));
See http://php.net/array_diff_key.
function array_ignore_index($id,$item){ ///function
unset($item[$id]);
return $item;
}
$a=array('id'=>1,
'name'=>'name');
$b=array_ignore_index('name',$a);
echo $b['name']; //create error id is not present
Here is the code for required operation..
You can use unset array column
Code is
unset($item['id']);
To test it
print_r($item);
Working with an array file with following structure. I know there are additional arrays that need to be inserted under each array 'color'.
$items=array (
0 =>
array (
'color' => 'category_a',
),
1 =>
array (
'book' => 'Gone With The Wind',
'movie' => 'GWTW',
'id'=> 'A100'
),
2 =>
array (
'book' => 'Goldfinger',
'movie' => 'GF',
'id'=> 'A103'
),
3 =>
array (
'color' => 'category_b',
),
4 =>
array (
'book' => 'Across The Great Dvide',
'movie' => 'ATGD',
'id'=> 'B102'
),
5 =>
array (
'book' => 'Goldfinger',
'movie' => 'GF',
'id'=> 'B103'
),
);
Once this array is created, I am using a list to loop thru to verify that each value in the list is placed in each 'color' array as follows
foreach ($controllist as $key=>$value){
foreach($items as $item){
if(in_array($value['book'],$item){
echo "PRESENT IN ARRAY"."<BR>";
}else{
echo "INSERT INTO ARRAY HERE"."<BR>";
}
}
}
For simplicity my controllist looks like
Gone With The wind
Across The Great Divide
Goldfinger
Once complete I should end up with the info for Across The Great Divide inserted into 'color'=> 'category a' as the [2] with Goldfinger moving down one. In 'color'=>category_b' the first array should be Gone With The Wind. Any of the 'color' arrays could be missing an array at any position. To sum it up, need to check for the existence of a value from the list, if not present insert into the array. Other than using the foreach loops shown is there an easier way of doing this? If not how can I get the information inserted into the proper position?
Thanks
EDIT:
I believe the question may not be clear. What I need to do is check for the existence of one array in another. If the value in conrollist is not present in the array, insert an array into the array according the position in the conrollist. The inserted array will have the same structure as the others (I can take care of this part). I am having trouble determining if it exist and if not inserting it. Hope this helps
You might want to be using a for loop instead so you have a pointer on each iteration in order to determine where you are in the array.
foreach($items as $item){
for($i = 0; $i < count($controllist); $i++) {
if(in_array($controllist[$i]['book'],$item){
echo "PRESENT IN ARRAY AT POS ".$i."<BR>";
}else{
$controllist[$i]['book'] = $yourvar;
echo "INSERT INTO ARRAY HERE"."<BR>";
}
}
}
I would like to retrieve the first key from this multi-dimensional array.
Array
(
[User] => Array
(
[id] => 2
[firstname] => first
[lastname] => last
[phone] => 123-1456
[email] =>
[website] =>
[group_id] => 1
[company_id] => 1
)
)
This array is stored in $this->data.
Right now I am using key($this->data) which retrieves 'User' as it should but this doesn't feel like the correct way to reach the result.
Are there any other ways to retrieve this result?
Thanks
There are other ways of doing it but nothing as quick and as short as using key(). Every other usage is for getting all keys. For example, all of these will return the first key in an array:
$keys=array_keys($this->data);
echo $keys[0]; //prints first key
foreach ($this->data as $key => $value)
{
echo $key;
break;
}
As you can see both are sloppy.
If you want a oneliner, but you want to protect yourself from accidentally getting the wrong key if the iterator is not on the first element, try this:
reset($this->data);
reset():
reset() rewinds array 's internal
pointer to the first element and
returns the value of the first array
element.
But what you're doing looks fine to me. There is a function that does exactly what you want in one line; what else could you want?
Use this (PHP 5.5+):
echo reset(array_column($this->data, 'id'));
I had a similar problem to solve and was pleased to find this post. However, the solutions provided only works for 2 levels and do not work for a multi-dimensional array with any number of levels. I needed a solution that could work for an array with any dimension and could find the first keys of each level.
After a bit of work I found a solution that may be useful to someone else and therefore I included my solution as part of this post.
Here is a sample start array:
$myArray = array(
'referrer' => array(
'week' => array(
'201901' => array(
'Internal' => array(
'page' => array(
'number' => 201,
'visits' => 5
)
),
'External' => array(
'page' => array(
'number' => 121,
'visits' => 1
)
),
),
'201902' => array(
'Social' => array(
'page' => array(
'number' => 921,
'visits' => 100
)
),
'External' => array(
'page' => array(
'number' => 88,
'visits' => 4
)
),
)
)
)
);
As this function needs to display all the fist keys whatever the dimension of the array, this suggested a recursive function and my function looks like this:
function getFirstKeys($arr){
$keys = '';
reset($arr);
$key = key($arr);
$arr1 = $arr[$key];
if (is_array($arr1)){
$keys .= $key . '|'. getFirstKeys($arr1);
} else {
$keys = $key;
}
return $keys;
}
When the function is called using the code:
$xx = getFirstKeys($myArray);
echo '<h4>Get First Keys</h4>';
echo '<li>The keys are: '.$xx.'</li>';
the output is:
Get First Keys
The keys are: referrer|week|201901|Internal|page|number
I hope this saves someone a bit of time should they encounter a similar problem.