I have the following array (example, real one is larger)
Array
(
[0] => Array
(
[984ab6aebd2777ff914e3e0170699c11] => Array
(
[id] => 984ab6aebd2777ff914e3e0170699c11
[message] => Test1
)
[1] => Array
(
[ca403872d513404291e914f0cad140de] => Array
(
[id] => ca403872d513404291e914f0cad140de
[message] => Test2
)
)
[2] => Array
(
[ca403872d513404291e914f0cad140de] => Array
(
[id] => ca403872d513404291e914f0cad140de
[message] => Test3
)
[3] => Array
(
[ca403872d513404291e914f0cad140de] => Array
(
[id] => ca403872d513404291e914f0cad140de
[message] => Test4
)
)
)
Now I want to somehow "access" the subarray with a given id, e.g. access the subarray with ID 984ab6aebd2777ff914e3e0170699c11 and then proceed to use this array in a foreach like this..
foreach ($array_with_specific_id as $event) {
echo $event['message'];
}
Is this possible?
Edit:
DB code to produce array in my model:
public function get_event_timeline($id)
{
$data = array();
foreach ($id as $result) {
$query = $this->db->query("SELECT * FROM event_timeline WHERE id = ?", array($result['id']));
foreach ($query->result_array() as $row)
{
array_push($data, array($row['id'] => $row));
}
}
return $data;
}
When populating your array from the database you can cerate an additional $index array like the following scheme:
$index = array (
'984ab6aebd2777ff914e3e0170699c11' => ReferenceToElementInData,
'ca403872d513404291e914f0cad140de' => ReferenceToElementInData,
// ...
)
This can give you quick access to the elements via their id without an additional foreach loop. Of course it will need additional memory, but this should be ok as you will only save refrences to the original data. However, test it.
Here comes an example:
public function get_event_timeline($id)
{
$data = array();
// create an additional index array
$index = array();
// counter
$c=0;
foreach ($id as $result) {
$query = $this->db->query("SELECT * FROM event_timeline WHERE id = ?", array($result['id']));
// every entry in the index is an array with references to entries in $data
$index[$result['id']] = array();
foreach ($query->result_array() as $row)
{
array_push($data, array($row['id'] => $row));
// create an entry in the current index
$index[$row['id']][] = &$data[$c];
$c++;
}
}
return array (
'data' => $data,
'index' => $index
);
}
Now you can access the elements via the index array without an additional foreach loop:
$entry = $index['984ab6aebd2777ff914e3e0170699c11'][0];
If there are multiple results per $id (as you mentioned in the comments you can access them using index greater then zero:
$entry = $index['984ab6aebd2777ff914e3e0170699c11'][1];
$entry = $index['984ab6aebd2777ff914e3e0170699c11'][2];
You can get the count of items per $id by calling
$number = count($index['984ab6aebd2777ff914e3e0170699c11']);
That's much the same like indexes that where used in databases to speed up queries.
I'd probably just get rid of the containing array as it seems unnecessary. However, you could do something like:
function get_message($specific_id, $arrays) {
foreach($arrays as $array) {
if(in_array($specific_id, $array)) {
return $array['message'];
}
}
}
I haven't had a chance to test this, but it should work.
function doTheJob($inputArray, $lookingFor) {
foreach ($inputArray as $subArray) {
foreach ($subArray as $subKey => $innerArray) {
if ($subKey == $lookingFor) {
return $innerArray;
}
}
}
return NULL;
}
Alternatively, you can use array_filter instead of outer foreach.
Related
Fetching multi-row data from MySQL database and trying to convert the results into a single array. Since the data is coming from a custom function where modifying it will break many other things, I can't change the way the way it is fetched so must process after retrieval using PHP. This is a sample:
Array
(
[0] => Array
(
[FieldLabel] =>
[FieldName] => ID
[FieldValue] => $ID
[FieldType] => 0
)
[1] => Array
(
[FieldLabel] => Name
[FieldName] => Name
[FieldValue] => $FieldName
[FieldType] => 1
)
)
Looking for something like this with only all the values in a single array but with the variables populated:
Array('','ID',$ID,0,'Name','Name',$FieldName,1)
I found this little function in another post that seemed would at lease create the array it but unfortunately it does not and I don't know enough about array manipulation to be able to sort it out. Any ideas?
function array2Recursive($array) {
$lst = array();
foreach( array_keys($array) as $k ) :
$v = $array[$k];
if (is_scalar($v)) :
$lst[] = $v;
elseif (is_array($v)) :
$lst = array_merge($lst,array2Recursive($v));
endif;
endforeach;
return array_values(array_unique($lst));
}
On way to solve this could be to use a foreach to loop through the items and add them to an array:
$result = [];
foreach ($array as $a) {
foreach($a as $item) {
$result[] = $item;
}
}
print_r($result);
Demo
I want to consolidate an associative array of indexed arrays by merging rows which have an associative key that is in another row's values.
Consider this sample input:
$array = [
44259 => [50007, 50009, 46372],
50007 => [50008],
50009 => [50010],
66666 => ['no', 'other', 'links'],
46372 => [46418, 46419, 46421],
46421 => [146880]
];
Because the values in the 44259-keyed row (50007, 50009, and 46372) exist as keys in the original array, all of the values from those values should be pushed into the 44259-keyed row.
Continuing the same logic, after the 46372-keyed rows have been added to 44259-keyed row, now the 46421-keyed row values should be pushed into the growing 44259-keyed row.
Desired result:
$array = [
44259 => [
50007, // original
50009, // original
46372, // original
50008, // from 50007
50010, // from 50009
50018, // from 46372
46419, // from 46372
46421, // from 46372
146880, // from 46372 -> 46421
66666 => [
'no',
'other',
'links'
]
];
You see, this is somewhat of a recursive task.
I tried this already:
foreach ($array as $cid => $pid) {
foreach ($pid as $pip) {
if (isset($array[$pipp])) {
foreach ($array[$pipp] as $pip) {
$array[$cid][] = $pip;
unset($array[$pipp]);
}
}
}
}
But it's not properly collecting the 46372 row's data for the 44259 row.
You could get the first key using array_keys() and reset(). Then you could add values of all array to this key:
$array = [];
$array[44259] = [50007, 50009, 46372];
$array[50007] = [50008];
$array[50009] = [50010];
$array[46372] = [46418, 46419, 46421];
$array[46421] = [146880];
$out = [];
$keys = array_keys($array);
$first_key = reset($keys); // $first_key = 44259
foreach ($array as $k => $items) {
foreach ($items as $val) {
$out[$first_key][] = $val;
}
}
print_r($out);
Outputs:
Array
(
[44259] => Array
(
[0] => 50007
[1] => 50009
[2] => 46372
[3] => 50008
[4] => 50010
[5] => 46418
[6] => 46419
[7] => 46421
[8] => 146880
)
)
You coukd try just merging
$result =array_merge($array[44259],$array[50007] ,$array[50009] ,
$array[46372], $array[46421] );
$res = array();
$res[44259] = array();
foreach($array as $pid)
$res[44259] = array_merge($res[44259], $pid);
print_r($res);
?>
Ouput
Array
(
[44259] => Array
(
[0] => 50007
[1] => 50009
[2] => 46372
[3] => 50008
[4] => 50010
[5] => 46418
[6] => 46419
[7] => 46421
[8] => 146880
)
)
This is probably one way of doing it. Create another array and push all the variables in the new array.
$result=[];
foreach ($array as $v1) {
foreach ($v1 as $v2) {
array_push($result,$v2);
}
}
Have you tried array_merge?
$mergedArray = [];
foreach ($array as $subArray) {
$mergedArray = array_merge ($mergedArray, $subArray);
}
If that doesn't work, then you could probably use array_map to run a function on each sub array element to check if it is in the merged array before adding it.
$mergedArray = [];
foreach ($array as $subArray) {
array_map(function($elm) {
if (!in_array($elm, $mergedArray)) {
$mergedArray[] = $elm;
}, $subArray);
}
You were very close, but you need to allow your script to restart the full array loop after consolidating data.
I recommend a do{}while() loop so that the inner processing can be repeated until there are no qualifying/moveable rows.
A nested loop is then used to search for first level keys that match any of the row values. Make the rows modifiable by reference with & -- this will ensure that the data manipulations are upon the original array and not merely a copy of the original array.
When there is a matching key, push the entire found row into the parent row, then remove the now-empty row from the original array, then toggle the flag indicating that another loop is required, then break
Code: (Demo)
do {
$changes = false;
foreach ($array as $k => &$row) {
foreach ($row as $v) {
if (isset($array[$v])) {
array_push($array[$k], ...$array[$v]);
unset($array[$v]);
$changes = true;
}
}
}
} while($changes);
var_export($array);
I'm trying to code a system which will find user accounts that are using the same IPs, and print out the matches with their keys. I have already coded the part where the data is pulled from MySQL and nicely put in a multidimensional associative array, so input looks like this (the key is UserID, values are IP addresses):
$users = array(
100 => array("1.1.1.1","2.2.2.2","3.3.3.3"),
200 => array("1.1.1.1","4.4.4.4","5.5.5.5"),
300 => array("1.1.1.1","4.4.4.4","7.7.7.7")
);
The expected output would be:
Array
(
[1.1.1.1] => Array
(
[0] => 100
[1] => 200
[2] => 300
)
[4.4.4.4] => Array
(
[0] => 200
[1] => 300
)
)
I have searched and used trial and error with multiple nested foreach that would loop through the arrays, tried array_intersect to find the duplicates, but nothing gets me close to the expected output. By now I think I'm overthinking the problem and the solution is really easy, but I cannot seem to get close to the expected output. Any help is appreciated, thank you.
$output = array();
// loop through each user
foreach ($users as $id => $ips) {
// loop through each IP address
foreach ($ips as $ip) {
// add IP address, if not present
if (!isset($output[$ip])) {
$output[$ip] = array();
}
// add user ID to the IP address' array
$output[$ip][] = $id;
}
}
$users = array(
100 => array("1.1.1.1","2.2.2.2","3.3.3.3"),
200 => array("1.1.1.1","4.4.4.4","5.5.5.5"),
300 => array("1.1.1.1","4.4.4.4","7.7.7.7")
);
$allIP = [];
foreach ( $users as $user ) {
$allIP = array_merge($allIP, $user);
}
$allIP = array_unique($allIP);
$result = [];
foreach ( $allIP as $ip ) {
foreach ( $users as $key => $val ) {
if ( in_array($ip, $val, true) ) {
if ( !isset($result[$ip]) ) {
$result[$ip] = [];
}
array_push($result[$ip], $key);
}
}
}
$result = array_filter($result, function ($v, $k) {
if ( count($v) > 1 ) {
return true;
} else {
return false;
}
}, ARRAY_FILTER_USE_BOTH);
var_dump($result);
Although I think it's better to do this by SQL as well. It could be extremely slow to achieve this by PHP.
The multiple array looks like
Array
(
[id] => description
[header] =>
[width] => 20
[dbfield] => description
[type] => text
)
Array
(
[id] => quantity
[header] => Menge
[dbfield] => QUANTITY_NEW
[width] => 60
[type] => decimal
)
How can I get the value from dbfield where id is 'quantity' without knowing the numeric value of the id?
The actual code looks like
foreach($array as $id => $fieldData) {
if($fieldData['type'] == 'decimal')
{
doSomething...();
}
}
In the part with doSomething I need access to other fields from the array, but I only know the id. I already tried it with dbfield['quantity']['dbfield'] etc. which obviously fails.
A simple alternative using array_keys:
function getValues($data, $lookForValue, $column)
{
$res = array();
foreach ($data as $key => $data)
{
if($idx = array_keys($data, $lookForValue))
{
$res[$idx[0]] = $data[$column];
}
}
return $res;
}
$values = getValues($myData, "quantity", "dbfield");
var_dump($values);
echo out the array as such..
$array = array();
$array['qty'] = 'qtty';
$array['dbfield'] = 'QUANTITY_NEW';
if($array['qty'] = 'qtty'){
echo $array['dbfield'];
}
returns - QUANTITY_NEW
You can do this with several methods, one of them is using array_map to get those values:
$dbfield = array_filter(array_map(function($a){
if($a["id"] === "quantity"){
return $a["dbfield"];
}
}, $array));
print_r($dbfield);
You iterate over the array, and return the key dbfield where id is 'quantity'. Array filter is just to not return null values where it doesn't have 'quantity' id.
Online attempt to reproduce your code can be found here
I have two multidimensional arrays. First one $properties contains english names and their values. My second array contains the translations. An example
$properties[] = array(array("Floor"=>"5qm"));
$properties[] = array(array("Height"=>"10m"));
$translations[] = array(array("Floor"=>"Boden"));
$translations[] = array(array("Height"=>"Höhe"));
(They are multidimensional because the contains more elements, but they shouldn't matter now)
Now I want to translate this Array, so that I its at the end like this:
$properties[] = array(array("Boden"=>"5qm"));
$properties[] = array(array("Höhe"=>"10m"));
I have managed to build the foreach construct to loop through these arrays, but at the end it is not translated, the problem is, how I tell the array to replace the key with the value.
What I have done is this:
//Translate Array
foreach ($properties as $PropertyArray) {
//need second foreach because multidimensional array
foreach ($PropertyArray as $P_KiviPropertyNameKey => $P_PropertyValue) {
foreach ($translations as $TranslationArray) {
//same as above
foreach ($TranslationArray as $T_KiviTranslationPropertyKey => $T_KiviTranslationValue) {
if ($P_KiviPropertyNameKey == $T_KiviTranslationPropertyKey) {
//Name found, save new array key
$P_KiviPropertyNameKey = $T_KiviTranslationValue;
}
}
}
}
}
The problem is with the line where to save the new key:
$P_KiviPropertyNameKey = $T_KiviTranslationValue;
I know this part is executed correctly and contains the correct variables, but I believe this is the false way to assing the new key.
This is the way it should be done:
$properties[$oldkey] = $translations[$newkey];
So I tried this one:
$PropertyArray[$P_KiviPropertyNameKey] = $TranslationArray[$T_KiviTranslationPropertyKey];
As far as I understood, the above line should change the P_KiviPropertyNameKey of the PropertyArray into the value of Translation Array but I do not receive any error nor is the name translated. How should this be done correctly?
Thank you for any help!
Additional info
This is a live example of the properties array
Array
(
[0] => Array
(
[country_id] => 4402
)
[1] => Array
(
[iv_person_phone] => 03-11
)
[2] => Array
(
[companyperson_lastname] => Kallio
)
[3] => Array
(
[rc_lot_area_m2] => 2412.7
)
[56] => Array
(
[floors] => 3
)
[57] => Array
(
[total_area_m2] => 97.0
)
[58] => Array
(
[igglo_silentsale_realty_flag] => false
)
[59] => Array
(
[possession_partition_flag] => false
)
[60] => Array
(
[charges_parkingspace] => 10
)
[61] => Array
(
[0] => Array
(
[image_realtyimagetype_id] => yleiskuva
)
[1] => Array
(
[image_itemimagetype_name] => kivirealty-original
)
[2] => Array
(
[image_desc] => makuuhuone
)
)
)
And this is a live example of the translations array
Array
(
[0] => Array
(
[addr_region_area_id] => Maakunta
[group] => Kohde
)
[1] => Array
(
[addr_town_area] => Kunta
[group] => Kohde
)
[2] => Array
(
[arable_no_flag] => Ei peltoa
[group] => Kohde
)
[3] => Array
(
[arableland] => Pellon kuvaus
[group] => Kohde
)
)
I can build the translations array in another way. I did this like this, because in the second step I have to check, which group the keys belong to...
Try this :
$properties = array();
$translations = array();
$properties[] = array("Floor"=>"5qm");
$properties[] = array("Height"=>"10m");
$translations[] = array("Floor"=>"Boden");
$translations[] = array("Height"=>"Höhe");
$temp = call_user_func_array('array_merge_recursive', $translations);
$result = array();
foreach($properties as $key=>$val){
foreach($val as $k=>$v){
$result[$key][$temp[$k]] = $v;
}
}
echo "<pre>";
print_r($result);
output:
Array
(
[0] => Array
(
[Boden] => 5qm
)
[1] => Array
(
[Höhe] => 10m
)
)
Please note : I changed the array to $properties[] = array("Floor"=>"5qm");, Removed a level of array, I guess this is how you need to structure your array.
According to the structure of $properties and $translations, you somehow know how these are connected. It's a bit vague how the indices of the array match eachother, meaning the values in $properties at index 0 is the equivalent for the translation in $translations at index 0.
I'm just wondering why the $translations array need to have the same structure (in nesting) as the $properties array. To my opinion the word Height can only mean Höhe in German. Representing it as an array would suggest there are multiple translations possible.
So if you could narrow down the $translations array to an one dimensional array as in:
$translation = array(
"Height"=>"Höhe",
"Floor"=>"Boden"
);
A possible loop would be
$result = array();
foreach($properties as $i => $array2) {
foreach($array2 as $i2 => $array3) {
foreach($array3 as $key => $value) {
$translatedKey = array_key_exists($key, $translations) ?
$translations[$key]:
$key;
$result[$i][$i2][$translatedKey] = $value;
}
}
}
(I see every body posting 2 loops, it's an array,array,array structure, not array,array ..)
If you cannot narrow down the translation array to a one dimensional array, then I'm just wondering if each index in the $properties array matches the same index in the $translations array, if so it's the same trick by adding the indices (location):
$translatedKey = $translations[$i][$i2][$key];
I've used array_key_exists because I'm not sure a translation key is always present. You have to create the logic for each case scenario yourself on what to check or not.
This is a fully recursive way to do it.
/* input */
$properties[] = array(array("Floor"=>"5qm", array("Test"=>"123")));
$properties[] = array(array("Height"=>"10m"));
$translations[] = array(array("Floor"=>"Boden", array("Test"=>"Foo")));
$translations[] = array(array("Height"=>"Höhe"));
function array_flip_recursive($arr) {
foreach ($arr as $key => $val) {
if (is_array($val)) {
$arr[$key] = array_flip_recursive($val);
}
else {
$arr = #array_flip($arr);
}
}
return $arr;
}
function array_merge_it($arr) {
foreach ($arr as $key => $val) {
if (is_array($val)) {
$arr[$key] = array_merge_it($val);
} else {
if(isset($arr[$key]) && !empty($arr[$key])) {
#$arr[$key] = $arr[$val];
}
}
}
return $arr;
}
function array_delete_empty($arr) {
foreach ($arr as $key => $val) {
if (is_array($val)) {
$arr[$key] = array_delete_empty($val);
}
else {
if(empty($arr[$key])) {
unset($arr[$key]);
}
}
}
return $arr;
}
$arr = array_replace_recursive($properties, $translations);
$arr = array_flip_recursive($arr);
$arr = array_replace_recursive($arr, $properties);
$arr = array_merge_it($arr);
$arr = array_delete_empty($arr);
print_r($arr);
http://sandbox.onlinephpfunctions.com/code/d2f92605b609b9739964ece9a4d8f389be4a7b81
You have to do the for loop in this way. If i understood you right (i.e) in associative array first key is same (some index).
foreach($properties as $key => $values) {
foreach($values as $key1 => $value1) {
$propertyResult[] = array($translations[$key][$key1][$value1] => $properties[$key][$key1][$value1]);
}
}
print_r($propertyResult);