Multisort a 2 deep array - php

Consider the following multisort method. In this case I have a array of items with a specific start date. Example array is shown:
0 -> array('title' => 'hello',
'attributes' => array('id' => 4, 'startdate' => '2013-06-11')),
1 -> array('title' => 'hello second entry',
'attributes' => array('id' => 6, 'startdate' => '2013-04-11'))
You can see that the 2nd entry should come before the first. Using my call currently will not work because It only checks to depth 1 of the array.
$albums = $this->multiSort($items, "SORT_ASC", 'startdate', true);
How would be the best way to modify this method to have a depth search on the items in the array. Even better would be to be able to specific the depth key. I would like to avoid having to add additional parameters to the method.
I could call the method like so and then write a for loop to get the key data, but having nested for loops is not something I want to do.
$albums = $this->multiSort($items, "SORT_ASC", array('attributes', 'startdate') , true);
What is the best way to optimize this method for my case?
public function multiSort($data, $sortDirection, $field, $isDate) {
if(empty($data) || !is_array($data) || count($data) < 2) {
return $data;
}
foreach ($data as $key => $row) {
$orderByDate[$key] = ($isDate ? strtotime($row[$field]) : $row[$field]);
}
if($sortDirection == "SORT_DESC") {
array_multisort($orderByDate, SORT_DESC, $data);
} else {
array_multisort($orderByDate, SORT_ASC, $data);
}
return $data;
}

UPDATED. This allows you to pass in a string for field that is delimited and is a path to your desired field.
$items = Array();
$items[0] = array('title' => 'hello',
'attributes' => array('id' => 4, 'startdate' => '2013-06-11'));
$items[1] = array('title' => 'hello second entry',
'attributes' => array('id' => 6, 'startdate' => '2013-04-11'));
function multiSort($data, $sortDirection, $field, $isDate) {
if(empty($data) || !is_array($data) || count($data) < 2) {
return $data;
}
// Parse our search field path
$parts = explode("/", $field);
foreach ($data as $key => $row) {
$temp = &$row;
foreach($parts as $key2) {
$temp = &$temp[$key2];
}
//$orderByDate[$key] = ($isDate ? strtotime($row['attributes'][$field]) : $row['attributes'][$field]);
$orderByDate[$key] = ($isDate ? strtotime($temp) : $temp);
}
unset($temp);
if($sortDirection == "SORT_DESC") {
array_multisort($orderByDate, SORT_DESC, $data);
} else {
array_multisort($orderByDate, SORT_ASC, $data);
}
return $data;
}
$albums = multiSort($items, "SORT_ASC", 'attributes/startdate', true);
print_r($albums);
Ouput:
Array
(
[0] => Array
(
[title] => hello second entry
[attributes] => Array
(
[id] => 6
[startdate] => 2013-04-11
)
)
[1] => Array
(
[title] => hello
[attributes] => Array
(
[id] => 4
[startdate] => 2013-06-11
)
)
)

Related

Search in a multidimensional assoc array

I have an array, looking like this:
[lund] => Array
(
[69] => foo
)
[berlin] => Array
(
[138] => foox2
)
[tokyo] => Array
(
[180] => foox2
[109] => Big entrance
[73] => foo
)
The thing is that there were duplicate keys, so I re-arranged them so I can search more specifically, I thought.
Previously I could just
$key = array_search('foo', $array);
to get the key but now I don't know how.
Question: I need key for value foo, from tokyo. How do I do that?
You can get all keys and value of foo by using this:
foreach ($array as $key => $value) {
$newArr[$key] = array_search('foo', $value);
}
print_r(array_filter($newArr));
Result is:
Array
(
[lund] => 69
[tokyo] => 109
)
If you don't mind about the hard code than you can use this:
array_search('foo', $array['tokyo']);
It just a simple example, you can modify it as per your requirement.
Try this
$a = array(
"land"=> array("69"=>"foo"),
"land1"=> array("138"=>"foo1"),
"land2"=> array('180' => 'foox2',
'109' => 'Big entrance',
'73' => 'foo'),
);
//print_r($a);
$reply = search_in_array($a, "foo");
print_r($reply);
function search_in_array($a, $search)
{
$result = array();
foreach($a as $key1 => $array ) {
foreach($array as $k => $value) {
if($value == "$search") {
array_push($result,"{$key1}=>{$k}");
breck;
}
}
}
return $result;
}
This function will return the key or null if the search value is not found.
function search($searchKey, $searchValue, $searchArr)
{
foreach ($searchArr as $key => $value) {
if ($key == $searchKey && in_array($searchValue, $value)) {
$results = array_search($searchValue, $value);
}
}
return isset($results) ? $results : null;
}
// var_dump(search('tokyo', 'foo', $array));
Since Question: I need key for value foo, from tokyo. How do i do that?
$key = array_search('foo', $array['tokyo']);
As a function:
function getKey($keyword, $city, $array) {
return array_search($keyword, $array[$city]);
}
// PS. Might be a good idea to wrap this array in an object and make getKey an object method.
If you want to get all cities (for example to loop through them):
$cities = array_keys($array);
I created solution using array iterator. Have a look on below solution:
$array = array(
'lund' => array
(
'69' => 'foo'
),
'berlin' => array
(
'138' => 'foox2'
),
'tokyo' => array
(
'180' => 'foox2',
'109' => 'Big entrance',
'73' => 'foo'
)
);
$main_key = 'tokyo'; //key of array
$search_value = 'foo'; //value which need to be search
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach ($iterator as $key => $value) {
$keys = array();
if ($value == $search_value) {
$keys[] = $key;
for ($i = $iterator->getDepth() - 1; $i >= 0; $i--) {
$keys[] = $iterator->getSubIterator($i)->key();
}
$key_paths = array_reverse($keys);
if(in_array($main_key, $key_paths) !== false) {
echo "'{$key}' have '{$value}' value which traverse path is: " . implode(' -> ', $key_paths) . '<br>';
}
}
}
you can change value of $main_key and $serch_value according to your parameter. hope this will help you.
<?php
$lund = [
'69' => 'foo'
];
$berlin = [
'138' => 'foox2'
];
$tokyo = [
'180' => 'foox2',
'109' => 'Big entrance',
'73' => 'foo'
];
$array = [
$lund,
$berlin,
$tokyo
];
echo $array[2]['180']; // outputs 'foox2' from $tokyo array
?>
If you want to get key by specific key and value then your code should be:
function search_array($array, $key, $value)
{
if(is_array($array[$key])) {
return array_search($value, $array[$key]);
}
}
echo search_array($arr, 'tokyo', 'foo');
try this:
<?php
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'On');
$array=array("lund" => array
(
69 => "foo"
),
"berlin" => array
(
138 => "foox2"
),
"tokyo" => array
(
180 => "foox2",
109 => "Big entrance",
73 => "foo"
));
function search($array, $arrkey1, $arrvalue2){
foreach($array as $arrkey=>$arrvalue){
if($arrkey == $arrkey1){
foreach($arrvalue as $arrkey=>$arrvalue){
if(preg_match("/$arrvalue/i",$arrvalue2))
return $arrkey;
}
}
}
}
$result=search($array, "tokyo", "foo"); //$array=array; tokyo="inside array to check"; foo="value" to check
echo $result;
You need to loop through array, since its 2 dimensional in this case. And then find corresponding value.
foreach($arr as $key1 => $key2 ) {
foreach($key2 as $k => $value) {
if($value == "foo") {
echo "{$k} => {$value}";
}
}
}
This example match key with $value, but you can do match with $k also, which in this case is $key2.

PHP Find a value in a key and get the value of another key in a multi-dimentional array

Might be a newbie question but I've been trying to figure this problem and it's doing my head in.
I have the following array :
[0] => Array
(
[provisionalBookingRoomID] => 1
[totalSpecificRoomCount] => 2
)
[1] => Array
(
[provisionalBookingRoomID] => 2
[totalSpecificRoomCount] => 5
)
I need a php function that searches through the array for the value of 'provisionalBookingRoomID' and returns the value of 'totalSpecificRoomCount'
basically something like the following
getProvisionalTotalRoomsCount($currentRoom, $arrayOfRooms);
// getProvisionalTotalRoomsCount('1', $arrayOfRooms) should return 2;
Any ideas?
Check this:
getProvisionalTotalRoomsCount($currentRoom, $arrayOfRooms){
foreach($arrayOfRooms as $key=>$value){
if($value['provisionalBookingRoomID'] == $currentRoom){
return $value['totalSpecificRoomCount'];
}
}
}
For anyone looking for a generic function :
function findValueInArray($array, $searchValue, $searchKey, $requiredKeyValue) {
foreach($array as $key=>$value){
if($value[$searchKey] == $searchValue){
return $value[$requiredKeyValue];
}
}
}
// Usage : findValueInArray($provisionalBookedRoomsArray, '1', 'provisionalBookingRoomID', 'totalSpecificRoomCount');
If you are likely to work with more than one value, you could build a new array with a 1->1 map for those attributes.
<?php
$items = array(
array(
'name' => 'Foo',
'age' => 23
),
array(
'name' => 'Bar',
'age' => 47
)
);
// Php 7
$name_ages = array_column($items, 'name', 'age');
echo $name_ages['Foo']; // Output 23
// Earlier versions:
$name_ages = array();
foreach($items as $value)
{
$name_ages[$value['name']] = $value['age'];
}
echo $name_ages['Foo']; // Output 23
$value = 0;
$array = array(array("provisionalBookingRoomID"=>1,"totalSpecificRoomCount"=>2),array("provisionalBookingRoomID"=>2,"totalSpecificRoomCount"=>5));
array_map(
function($arr) use (&$value) {
if($arr['provisionalBookingRoomID']==1) {
$value = $arr['totalSpecificRoomCount'];
}
},$array
);
echo $value;

Foreach array to update table of database use those element of array

How to get the first value of element of array in php.
My story board is like this:
I have an array like this:
(
[0] => Array
(
[ID] => 68
[MATERIAL] => I have
[AC] => Try
)
[1] => Array
(
[ID] => 69
[MATERIAL] => It
[AC] => No Surrender
)
)
I want to update some record on my database like this,
foreach element of array,
UPDATE MY TABEL SET MATERIAL = [MATERIAL], AC = [AC] where id= [id]
this is the model named m_admin :
public function update_eir_to_cost($id, $material, $ac) {
$data = array(
"MATERIAL" => $material,
"AC" => $ac);
$this->db->trans_start();
$this->db->where($id);
$this->db->update('tb_repair_detail', $data);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
// generate an error... or use the log_message() function to log your error
echo "Error Updating";
} else {
echo "Alhamdulillah";
}
}
This is the controller :
public function update_json_detail() {
$post_data = $this->input->post("POST_ARRAY");
$execute = array();
foreach ($post_data as $data) {
$execute[] = array(
'ID'=> $data['0'],
'MATERIAL' => $data['7'],
'AC' => $data['8']
);
}
echo "<pre>";
print_r($execute); // return an array like above.
/*forech element
update table using model
*/
}
This will solve your problem:
public function update_json_detail() {
$post_data = $this->input->post("POST_ARRAY");
$execute = array();
foreach ($post_data as $data) {
$execute[] = array(
'ID'=> $data['0'],
'MATERIAL' => $data['7'],
'AC' => $data['8']
);
}
echo "<pre>";
print_r($execute); // return an array like above.
$this->load->model('m_admin');
foreach ($execute as $row) {
$this->m_admin->update_eir_to_cost($row['ID'], $row['MATERIAL'], $row['AC']);
}
}

Aggregate arrays in multilevel array if their values match

I have an array in the following format:
array(5){
[0] =>
array(4){
['product-id'] => 8931
['product'] => 'Cake'
['description'] => 'Yellow cake'
['quantity'] => 1
}
[1] =>
array(4){
['product-id'] => 8921
['product'] => 'Cookies'
['description'] => 'Chocolate chip cookies'
['quantity'] => 2
}
[2] =>
array(4){
['product-id'] => 8931
['product'] => 'Cake'
['description'] => 'Yellow cake'
['quantity'] => 1
}
[3] =>
array(4){
['product-id'] => 8931
['product'] => 'Cake'
['description'] => 'Yellow cake'
['quantity'] => 4
}
[4] =>
array(4){
['product-id'] => 8933
['product'] => 'Cake'
['description'] => 'Chocolate cake'
['quantity'] => 1
}
}
How can I compare all the arrays to each other?
In my code I have sorted all the arrays by product ID, and written a for to compare two rows at a time, but now I see why that won't work.
function cmp($a, $b){
return strcmp($a[0], $b[0]);
}
function combineArrays($arrays){
usort($arrays, "cmp");
for($i = 1; $i < count($arrays); $i++){
$f_row = $arrays[$i];
$next = $i + 1;
$s_row = $arrays[$next];
if($f_row[0] == $s_row[0]){
if($f_row[1] == $s_row[1]){
if($f_row[2] == $s_row[2]){
$q1 = (int) $f_row[3];
$q2 = (int) $s_row[3];
$total = $q1 + $q2;
unset($f_row[3]);
$f_row[5] = $total;
unset($arrays[$next]);
}
}
}
}
return $arrays;
}
What is a better way to do this?
For example, to take the first array and compare it to the next, value for value. As soon as one of the first 3 values doesn't match, you go on to compare that row to the next one. If all of the first three values match, add up the quantity value of the two arrays, assign that to the first array's quantity, and get rid of the second array. There could be more matches, so continue comparing that array until you have gone through the whole list.
My favorite solution uses array_reduce():
$filtered = array_reduce(
// Reduce the original list
$arrays,
// The callback function adds $item to $carry (the partial result)
function (array $carry, array $item) {
// Generate a key that contains the first 3 properties
$key = $item['product-id'].'|'.$item['product'].'|'.$item['description'];
// Search into the partial list generated until now
if (array_key_exists($key, $carry)) {
// Update the existing item
$carry[$key]['quantity'] += $item['quantity'];
} else {
// Add the new item
$carry[$key] = $item;
}
// The array_reduce() callback must return the updated $carry
return $carry;
},
// Start with an empty list
array()
);
try this
$arr=array(
array(
'product-id' => 8931,
'product' => 'Cake',
'description' => 'Yellow cake',
'quantity' => 3,
),
array(
'product-id' => 8921,
'product' => 'Cookies',
'description' => 'Chocolate chip cookies',
'quantity' => 2,
),
array(
'product-id' => 8931,
'product' => 'Cake',
'description' => 'Yellow cake',
'quantity' => 1,
)
);
$id = array();
foreach ($arr as $key => $row)
{
$id[$key] = $row['product-id'];
}
array_multisort($id, SORT_DESC, $arr);
$result = array();
foreach ($arr as $key => $row)
{
$pid = $row['product-id'];
if(!isset($result[$pid]))
{
$result[$pid]=$row;
}else{
$result[$pid]['quantity']+=$row['quantity'];
}
}
print_r($result);
You are doing it the hard way, why not do it like this:
function combineProducts($products) {
$result = array();
foreach ($products as $product) {
//if you can have different product or descriptions
//per product id you can change this this to
//$productId = implode('|', array($product['product-id'], $product['product'], $product['description']);
$productId = $product['product-id'];
//check if we already have this product
if (isset($result[$productId])) {
//add to the quantity
$result[$productId]['quantity']+= $product['quantity'];
} else {
$result[$productId] = $product;
}
}
//sort the results (remove if not needed)
ksort($result);
//return values (change to return $result; if you want an assoc array)
return array_values($result);
}

php, long and deep matrix

I have a deep and long array (matrix). I only know the product ID.
How found way to product?
Sample an array of (but as I said, it can be very long and deep):
Array(
[apple] => Array(
[new] => Array(
[0] => Array([id] => 1)
[1] => Array([id] => 2))
[old] => Array(
[0] => Array([id] => 3)
[1] => Array([id] => 4))
)
)
I have id: 3, and i wish get this:
apple, old, 0
Thanks
You can use this baby:
function getById($id,$array,&$keys){
foreach($array as $key => $value){
if(is_array( $value )){
$result = getById($id,$value,$keys);
if($result == true){
$keys[] = $key;
return true;
}
}
else if($key == 'id' && $value == $id){
$keys[] = $key; // Optional, adds id to the result array
return true;
}
}
return false;
}
// USAGE:
$result_array = array();
getById( 3, $products, $result_array);
// RESULT (= $result_array)
Array
(
[0] => id
[1] => 0
[2] => old
[3] => apple
)
The function itself will return true on success and false on error, the data you want to have will be stored in the 3rd parameter.
You can use array_reverse(), link, to reverse the order and array_pop(), link, to remove the last item ('id')
Recursion is the answer for this type of problem. Though, if we can make certain assumptions about the structure of the array (i.e., 'id' always be a leaf node with no children) there's further optimizations possible:
<?php
$a = array(
'apple'=> array(
'new'=> array(array('id' => 1), array('id' => 2), array('id' => 5)),
'old'=> array(array('id' => 3), array('id' => 4, 'keyname' => 'keyvalue'))
),
);
// When true the complete path has been found.
$complete = false;
function get_path($a, $key, $value, &$path = null) {
global $complete;
// Initialize path array for first call
if (is_null($path)) $path = array();
foreach ($a as $k => $v) {
// Build current path being tested
array_push($path, $k);
// Check for key / value match
if ($k == $key && $v == $value) {
// Complete path found!
$complete= true;
// Remove last path
array_pop($path);
break;
} else if (is_array($v)) {
// **RECURSION** Step down into the next array
get_path($v, $key, $value, $path);
}
// When the complete path is found no need to continue loop iteration
if ($complete) break;
// Teardown current test path
array_pop($path);
}
return $path;
}
var_dump( get_path($a, 'id', 3) );
$complete = false;
var_dump( get_path($a, 'id', 2) );
$complete = false;
var_dump( get_path($a, 'id', 5) );
$complete = false;
var_dump( get_path($a, 'keyname', 'keyvalue') );
I tried this for my programming exercise.
<?php
$data = array(
'apple'=> array(
'new'=> array(array('id' => 1), array('id' => 2), array('id' => 5)),
'old'=> array(array('id' => 3), array('id' => 4))
),
);
####print_r($data);
function deepfind($data,$findfor,$depth = array() ){
foreach( $data as $key => $moredata ){
if( is_scalar($moredata) && $moredata == $findfor ){
return $depth;
} elseif( is_array($moredata) ){
$moredepth = $depth;
$moredepth[] = $key;
$isok = deepfind( $moredata, $findfor, $moredepth );
if( $isok !== false ){
return $isok;
}
}
}
return false;
}
$aaa = deepfind($data,3);
print_r($aaa);
If you create the array once and use it multiple times i would do it another way...
When building the initial array create another one
$id_to_info=array();
$id_to_info[1]=&array['apple']['new'][0];
$id_to_info[2]=&array['apple']['new'][2];

Categories