Php merge arrays [duplicate] - php

This question already has answers here:
Is there a php function like python's zip?
(14 answers)
Closed 7 months ago.
So I have these two foreach
foreach($find as $e) {
$theData[] = array('href' => $e->href, 'linkText' => $e->plaintext);
foreach($findText as $f){
$theData[] = array('description' => $f->plaintext);
}
}
So I need that the result to be something like this: $theData = array('href' => $e->href, 'linkText' => $e->plaintext,'description' => $f->plaintext);
array_merge doesn't do want I want to achive.Any help?

Try...
$i = 0;
foreach($find as $e){
$data[$i] = array('href' => $e->href, 'linkText' => $e->plaintext);
foreach($findText as $f){
$data[$i]["description"][] = $f->plaintext;
}
$i++;
}

If your arrays both have automatically created integer keys, then it's simple:
$theData = array();
for($i = 0; $i < count($e); ++$i) {
$theData[] = array(
'href' => $find[$i]->href,
'linkText' => $find[$i]->plaintext,
'description' => $findText[$i]->plaintext);
}
Note that the above code will not work correctly if $find and $findText don't have the same number of items, or if the keys don't match. Generally, making this work without more specific information will get quite messy.
The best practical advice I can give is to re-examine the code which creates $find and $findText -- it will be much easier to achieve your goal at that time.

Allow me to make the assumption that you are combining information from two queries. One option you have is to get href, linktext and description from your database all at once by joining your query.
select table_1.href,table_1.plaintext, table_2.plaintext
from table_1
where //insert your where clause, if appropriate
join table_2 on table_1.id = table_2.parent_id
where table one is your $find array and table_2 is your $findText array; and table_2.parent_id is a value matching the id from table_1. Joining the tables in this query will store all the fields from your two assumed queries into one variable.

Related

How to use batch update/insert sql using codeigniter?

in this example.. how can i simplified and fasten up the update and insert of data in the database?
//if count($arr_list['sample_element1'] is 500+++ or more records
$i =0;
while ($i < count($arr_list['sample_element1'])) {
$update_db= array('column1' => $arr_list['sample_element1'][$i],'column2' => $arr_list['sample_element2'][$i]);
$this->db->update('sample_table',$update_db);
$i++;
}
if the record to be save is over 1000 data...it will take about sometime to finish the process.. thank in advance.. =)
use batch_update
$this->db->update(table_name,array,where_key_word);
here table_name = your table name
and array = an array containing multiple associative array
and where_key_word = the column which should be used in where condition
also read this question thread for more information
batch updating thousands of element together may create performance issue.Better split them up and update by smaller batch.Also use transactions so that if any of the update fails the whole update procedure can be rolled back
Taking #AL-zami's answer you're looking for this
$data = [];
$this->db->trans_start();
foreach($arr_list as $item)
{
$data[] = [
'column1' => $item['element1'],
'column2' => $item['element2'],
'column3' => $item['element3']
];
}
$this->db->update_batch('mytable', $data, 'column1');
$this->db->trans_complete();
Where 'column1' is the column used for the "WHERE" condition.

How to sort a multidimensional array of columns by a specific column in PHP?

I found on the PHP documentation the function "array_multisort" that is meant to sort an array "of columns". They provide one example where the user has an array of rows and then the user has to transform this array of rows into an array of columns. In my case the array is already set by columns, such as:
tablearray
{
['Employee_ID'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}
['First_Name'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}
['LastName'] = {0 => row1, 1 => row2, 2 => row3, 3 =>row4}
}
I want to sort by Employee_ID and I need all the other columns to follow the same order. I tried:
array_multisort($tablearray['Employee_ID'], SORT_ASC);
But it only sorts the first column (which becomes a mess). The array has more than 10 columns and it changes the column names depending on the search (the columns names are its keys).
On PHP's documentation for this function, the example provided shows that the after transforming the rows array into a columns array, we should use the original array as a third parameter to match the keys - I don't have the "original" array to do the match since I didn't transform anything.
Thank you.
Desired output, as suggested by one user:
Original:
array
{
['Employee_ID'] = (1002, 4508, 0002, 1112)
['Business_Unit'] = ('UER', 'ABC', 'XYZ', 'EER')
['LastName'] = ('Smith', 'Vicente', 'Simpson', 'Thompson')
}
Sorted by Employee ID:
array
{
['Employee_ID'] = (0002, 1002, 1112, 4508)
['Business_Unit'] = ('XYZ', 'UER', 'EER', 'ABC')
['LastName'] = ('Simpson','Smith', 'Thompson', 'Vicente')
}
--
My original array is a database query output:
Array
(
[0] => Array
(
[Employee_ID] => 0000
[Supervisor_ID] => 00000
[Location_Descr] => somewhere
[Start_Date] => 06/03/2002
[Service_Date] => 06/03/2002
[Rehire_Date] => 00/00/00
[Business_Unit] => YYYY
[Job_Title] => Manager
[Email] => email#example.com
[Dept_Desc] => bla bla bla
[Employee_Name_LF] => Last, First
[Supervisor_Name_LF] => Last, First
[Term_Date] => 00/00/00
[Preferred_Name] => Someone
[Source] => Sheet2
)
)
There a several more rows.
The main purpose is to show the results as an HTML table and to generate a CSV file. I already made those functions using the modified structure (the first that I posted). I thought it would be easier to deal with that structure... Indeed it was, but not for sorting unfortunately.
The array_multisort documentation (http://php.net/manual/en/function.array-multisort.php) suggests separating each column as an individual array.. However, as you can see I have several columns (and the user can select more or less to be shown before performing the query.. So I can't just list all of them on the statement).
I a willing to change everything just to make the code better to be worked with.
Ugly - would be a lot easier if you formatted the input tables.
$arr = array(
'Employee_ID' => array('1002', '4508', '0002', '1112'),
'Business_Unit' => array('UER', 'ABC', 'XYZ', 'EER'),
'LastName' => array('Smith', 'Vicente', 'Simpson', 'Thompson')
);
$employees = array();
foreach (range(0, sizeof($arr[current(array_keys($arr))]) - 1) as $k) {
$emp = array();
foreach ($arr as $col => $vals) {
$emp[$col] = $arr[$col][$k];
}
$employees[] = $emp;
}
$sort = array();
foreach ($employees as $k => $v) {
$sort[$k] = $v['Employee_ID'];
}
array_multisort($sort, SORT_ASC, $employees);
print_r($employees);
And to put back in the original format:
$arr_sorted = array();
foreach (array_keys($arr) as $col) {
$arr_sorted[$col] = array();
foreach ($employees as $emp) {
$arr_sorted[$col][] = $emp[$col];
}
}
print_r($arr_sorted);
Thank you for posting the extra details in your question, as they did help in understanding the intent of your question.Now, you didn't tell us how that table should look; If you want the employees one per row, or one per column. Which is kind of crucial to know. Normally one would have one employee per line, especially if this is to be exported to CVS. However, I have a suspicion that it's the latter you want. Otherwise you've gone about this in a very overly complicated manner.Point in case: Normal one-per-row layout:
<?php
$db = new PDO();
// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "e.employee_id, e.first_name, e.lastname, u.business_unit, s.email";
// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$query = <<<outSQL
SELECT {$Fields} FROM `unit` AS u
INNER JOIN `employee` AS e ON e.employee_id = u.unit_id
INNER JOIN `employee` AS s ON s.employee_id = u.supervisor_id
ORDER BY e.`employee_id`
outSQL;
$data = $db->query($query);
// Creating a printf() template for the output, to make the code easier to maintain.
$rowTemplate = <<<outHTML
<tr>
<td>%1\$d</td>
<td>%2\$s</td>
<td>%3\$s</td>
</tr>
outHTML;
// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
<thead>
<tr>
<th>ID</th>
<th>First name</th>
<th>Last name</th>
</tr>
</thead>
<tbody>
%s
</tbody>
</table>
outHTML;
// Regular table output, one employee per line.
$temp = '';
foreach ($data as $e) {
// hs() is a shortcut function to htmlspecialchars (), to prevent against XSS.
$temp .= sprintf($rowTemplate, $e['employee_id'], hs($e['first_name']), hs($e['lastname']));
}
// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);
If you want to do it one per column, it becomes a bit more intricate. Though, still a bit easier than your first attempt. :)
Namely, something like this:
<?php
$db = new PDO();
// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "employee_id, first_name, lastname";
// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$data = $db->query("SELECT {$Fields} FROM `employees` ORDER BY `employee_id`");
// We need to know how many columns we'll have. One per employee.
$columns = count ($data);
// Rows have a header in front of each line, and one td tag for each employee.
$rowTemplate = "\t\t<th>%s</th>\n".str_repeat("\t\t\t<td>%s</td>\n", $columns);
// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
<tbody>
%s
</tbody>
</table>
outHTML;
// Reformat the array to give us the data per-column.
$temp = array ();
foreach ($data as $field => $e) {
// Since we've already sorted the data in the database we don't need to do any further sorting here.
// Also note that I'm doing the escaping here, seeing as this array will only be used for output.
$temp['Employee ID'][] = intval($e['employee_id']);
$temp['First name'][] = hs($e['first_name']);
$temp['Last name'][] = hs($e['lastname']);
}
// Now we do the same as in the above example.
$rows = '';
foreach ($temp as $label => $l) {
// We have the label as the first template variable to be added, so put it as the first element.
array_unshift($l, $label);
// Add the current row of items to the output, using the previously established template.
$rows = vprintf($rowTemplate, $l);
}
// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);
PS: Haven't tested the code, but it should work.
I ran into his problem and after much angst found a really nice solution in the notes on the php manual page - I now have the following function which i use whenever I need to solve this type of problem.
function fnArrayOrderby(){
//function to sort a database type array of rows by the values in one or more column
//source http://php.net/manual/en/function.array-multisort.php - user notes
//example of use -> $sorted = fnArrayOrderby($data, 'volume', SORT_DESC, 'edition', SORT_ASC);
$args = func_get_args(); //Gets an array of the function's argument list (which can vary in length)
//echo "sorting ".$args[0]."<br>";
if (!isset($args[0])) { return;}
$data = array_shift($args); //Shift an element off the beginning of array
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}

Iterating through PHP array with duplicate records and deleting one record where a value = 0

I have a MySQL query using Laravel that I convert to a PHP Array.
The rows have values similar to this:
name | override | percentage
Eclipse | 1 | 50%
Eclipse | 0 | 75%
MySQL query
select * from table
Both rows (it's many more than just 2 in reality) have the same name, but one has override set to 0 and one has it set to 1.
How can I get rid of all records in my query result (PHP array) that are duplicates (determined by the name) AND have override set to 0? I want only the records that have been overridden with a new record which I have done, but I need a way to remove the records with override = 0, given that the records are the same but have a different percentage value.
How can this be done?
Thanks.
Try following query,
SELECT * from testtable GROUP BY `name` HAVING count(`name`) = 1 OR `override` = 1;
check this sqlfiddle
If I understand your needs correctly, you need to filter out records that have duplicate name and override = 0.
If you sort your result set by name (SELECT * FROM TABLE ORDER BY name), you can use this function.
function removeDuplicatesFromArray($rows) {
$result = array();
$old_name = '';
foreach($rows as $row) {
if($row['name'] != $old_name) {
$result[] = $row;
$old_name = $row['name'];
}
elseif($row['override'] == 1) {
array_pop($result);
$result[] = $row;
}
}
return $result;
}
NOTE: Doing this in SQL will be WAYYYYYYYYY faster and use far less memory. I would only try this PHP approach if you cannot modify the SQL for some reason.
Maybe try out... hit the db twice, first time only get non-overrides, then get the overrides in second pass -- coerce your arrays to be indexed by name and array_merge them. (Uses a fair chunk of memory given the number of arrays and copies - but it's easy to understand and keeps it simple.
$initial = get_non_overridden();
$override = get_overridden();
$init_indexed = index_by_name($initial);
$over_indexed = index_by_name($override);
$desired_result = array_merge($init_indexed, $over_indexed);
Assuming your database gives you a standard rowset (array of rows, where each row is a hash of fields->values). We want something that looks like this instead:
[
'Eclipse' => [
'name' => 'Eclipse',
'override' => '0',
'percentage' => '75%'
],
'Something' => [
'name' => 'Something',
'override' => '0',
'percentage' => '20%'
],
]
So index_by_name would be:
function index_by_name($rowset) {
$result = array();
foreach ($rowset as $row) {
$result[ $row['name'] ] = $row;
}
return $result;
}
There are ways to tweak your efficiency either in memory or run time, but that's the gist of what I was thinking.
array_merge then overwrites the initial ones with the overridden ones.
NOTE: this all assumes that there is only one row where Eclipse override is 1. If you have twenty Eclipse|0 and one Eclipse|1, this will work, if you have two Eclipse|1 you'd only see one of them... and there's no way to say which one.

How do I make a Multidimension-Array of MYSQL data via PHP

I want to create a Array with multidimension arrays from a database. The Database has 3 tables, one for vehicle, one for damages and one for damagesPhotos.
Table vehicle has two columns id and name
Table damages has four columns damagesID, vehicleID, damagesType and damagesDescription.
Table damagesPhotos has three columns damagesPhotoID and damagesID and damagesPhotoUrl
I need to combine thoose three columns into an array, that looks like this:
$vehicle = array(
"id" => "somestring",
"name" => "somestring",
"damages" => array(
"damagesType" => "somestring",
"damagesDescription" => "somestring",
"photoOfDamages" => array(
"damagesPhotoUrl" => "somestring"
)
)
);
My code looks like this, but is not working the right way.
$result = mysql_query( "SELECT * from vehicle v LEFT JOIN damages d ON v.id = d.vehicleID LEFT JOIN damagesPhotos p ON d.damagesID = p.damagesID WHERE d.damagesID = p.damagesID AND v.id = 1") or die(mysql_error());
$rowsResult = array();
while ($r = mysql_fetch_assoc($result))
{
$rowsResult [] = $r;
}
mysql_free_result($result);
echo json_encode($rowsResult);
...
/Morten
As its not possible in mysql, so we can write a script which gives all information about specific vehicle and with that data, we can create an array.
Refer following code.
$query = "SELECT * from vehicle v LEFT JOIN damages d ON v.id = d.vehicleID LEFT JOIN damagesPhotos p ON d.damagesID = p.damagesID WHERE d.damagesID = p.damagesID AND v.id = 1";
$result = mysql_query($query);
$i = 0;
$vehicle = array();
while($row = mysql_fetch_array($result)){
$vehicle[$i] = array(
"id" => $row[id],
"name" => $row[name],
"damages" => array(
"damagesType" => $row[damagesType],
"damagesDescription" => $row[damagesDescription],
"photoOfDamages" => array(
"damagesPhotoUrl" => $row[damagesPhotoUrl]
)
)
);
$i++;
}
You can't get a multidimensional array from mysql, it just gives you a two dimensional resultset. A number of column values for each row is all you can get. If you want it nested like that, you'll have to process the array after retrieving the results.
Something like this:
$vehicles = array();
while ($r = mysql_fetch_assoc($result))
{
$vehicle['id'] = $r['id'];
...
$damage = array();
$damage['damagesType'] = $r['damagesType'];
...
$vehicle['damages'] = $damage;
...
array_push($vehicles, $vehicle);
}
echo json_encode($vehicles);
It is not possible to have MySQL do all the work for you here (well, it is possible to have it do most of the work, but don't) because a result set from MySQL - or any SQL driven database - can have exactly two dimensions. The first dimension is a collection of rows, and the second is a collection of columns for each row.
Based on the example target data structure, you have two choices:
Get the initial result set (vehicle LEFT JOIN damages) and iterate over it, running queries to get the photos
Join all tables together as you are currently doing and post-process it into the desired multidimensional structure.
It's a trade off - option 1 results in a lot more database traffic but retrieves no more than the required data, whereas option 2 reduces it to a single query with less database traffic, but retrieves more data than required because each photo row carries the entire vehicle's data with it.
Option 1 would be a prime candidate for using prepared statements, which is something you are unable to take advantage of using the mysql_* functions. You should switch to using PDO or MySQLi instead. I personally recommend PDO. There are numerous other reasons for doing this as well, including the fact that the MySQL extension will one day be removed from PHP, and the proper use of prepared statements can completely removed any risk of security problems resulting from SQL injection via user input.
I would probably recommend option 2.
Thanks to Vinay, my array looks like this. Thats nice :)
[{"vehilceId":"1",
"name":"AW55005",
"damages":{
"damagesType":"Exterior",
"damagesDescription":"Rust",
"photoOfDamages":{
"damagesPhotoUrl":"link to damagesPhoto 01"
}
}
},
{"vehilceId":"1",
"name":"AW55005",
"damages":{
"damagesType":"Exterior",
"damagesDescription":"Rust",
"photoOfDamages":{
"damagesPhotoUrl":"link to damagesPhoto 02"
}
}
},
{"vehilceId":"1",
"name":"AW55005",
"damages":{
"damagesType":"Interior",
"damagesDescription":"Scratch",
"photoOfDamages":{
"damagesPhotoUrl":"link to damagesPhoto 03"
}
}
}
But as you can see the first two objects are the same only the damagesPhotoUrl is different.
How do I merge thoose two array so it will look like this:
{"vehilceId":"1",
"name":"AW55005",
"damages":{
"damagesType":"Exterior",
"damagesDescription":"Rust",
"photoOfDamages":{
{"damagesPhotoUrl":"link to damagesPhoto 01"},
{"damagesPhotoUrl":"link to damagesPhoto 02"}
}
}
}, ...
/Morten
After solving you main problem. I am writing this for new problem. As I know, you cant assign values to same key in your array means you cant allow to have duplicate keys. Because How would you access the value you want if more than one can have the same key. That's why you can choose another way to do merge your value. Re-arrange your array in following way.
$key = "damagesPhotoUrl";
$value = "link to damagesPhoto 01";
$array[$key][] = $value;
you can then access it as:
echo $array[$key][0];
echo $array[$key][1];
Its very late.... but if you using PDO then PDO::FETCH_COLUMN with PDO::FETCH_GROUP can make result in 3 dimensional array.
I think its limited, I'm not very SQL guy, but saying "You can't get a multidimensional array from mysql...or any SQL driven database - can have exactly two dimensions" can be not quite true.
Sorry for my English and off topic (this question is about mysql, not pdo)
http://php.net/manual/en/pdostatement.fetchall.php
(pseudo array):
array(
array(//group 1
array(
0=>item1,
0=>item2...
)
array(
0=>item1,
0=>item2...
)
array(
0=>item1,
0=>item2...
)
array(
0=>item1,
0=>item2...
)
)...
array(//group 2
array(
0=>item1,
0=>item2...
)
array(
0=>item1,
0=>item2...
)
)...
)

Create multidimensional array from database query

I have a database that stores accounts and subscriptions. An account can contain accounts and subscriptions and have more than three parent levels.
A row from the database query result looks something like this:
$array = (0 => array("level" => "2", "accountno" => "123124234", "accountname" => "Hansel", "parentaccountno" => "000213123", "subscription" => "5423213213", "username" => "Gretchen");
(Level 1 means that it is top level and it will have PARENTACCOUNTNO = null).
From this I am trying to create a multidimensional array which looks something like this:
accounts:
000213123
accounts:
123124234
name: Hansel
subscriptions:
5423213213
username: Gretchen
This is the code I have so far, which works really well on the first two levels. When there are are three levels or more things become more complicated, since each account only knows about its own parent:
$hierarchy = array();
foreach ($decode as $row) {
$accountno = $row["ACCOUNTNO"];
$msisdn = $row["MSISDN"];
if ($row["PARENTACCOUNTNO"] == null)
$base_array_key = $hierarchy["accounts"];
$base_array_key[$accountno] = array("name" => $row["ACCOUNTNAME"], "accounts" => array(), "subscriptions" => array());
$hierarchy["accounts"][$accountno]["accounts"]["321323123213"] = "blaha";
if ($row["MSISDN"] != null)
$hierarchy["accounts"][$accountno]["subscriptions"][$msisdn] = array("enduser" => $row["ENDUSER"]);
}
The solution I have in mind right now is to pass the base key from each iteration to the next iteration, and then if for example the previous level was two levels above this one just use some sort of string replace to remove the last two parts of the key.
Any better ideas? I am quite sure this is a shitty way of doing what I am trying to accomplish.
Do all your results look like that ? So then, where's are the parent accounts ? Or am i missing something ? I would simple rewrite the query to get a more "linear" result, like:
parentaccountno | accountno | accountname | bla
-----------------------------------------------
000213123 | 123124234 | Hansel | abc
When every result row looks like this, you can simple create your final array like that:
foreach ($decode as $row) {
$my_array = [ $row["parentaccountno"] ][ $row["accountno"] ]["accountname"] = $row["accountname"];
$my_array = [ $row["parentaccountno"] ][ $row["accountno"] ]["bla"] = $row["bla"];
}
Create a temporary associative array:
$all_records = array();
Populate it with the results you find in the database:
while($result = get_results_from_db()) {
$accountno = $result[accountno];
$all_records[$accountno] = $result;
}
Now you have an array indexed by account numbers so it's easy to find any record if you know it's account number. So you iterate through the array to associate children to parents:
$top_level_records = array();
foreach($all_records AS $record) {
$parentaccountno = $record[parentaccountno];
if(!empty($parentaccountno)) {
$parent = &$all_records[$record[parentaccountno]];
if(empty($parent['accounts']))
$parent['accounts'] = array()
$parent['accounts'][] = $record;
}
else {
$top_level_records[] = $record;
}
}
I appreciate the answers, but I think the problem is my database query which should contain records of all the parents of an account and not just the parent, using something like SYS_CONNECT_BY_PATH in Oracle SQL.

Categories