I have case by equating the existing data
i Have 2 data with format like this
$data1 = "144|aku|1!!!122|dia|2"; data description "id|name|amount"
$data2 = "144|aku|1!!!211|dia|1";
there is the same data in 2 arrays, how to make the same data in the amount section can be added and unequal data will be inserted into the array
how to make the 2 arrays become like this
$data_result = "144|aku|2!!!122|dia|2!!!211|dia|1";
this my full script
$data1 = "144|aku|1!!!122|dia|2";
$data2 = "144|aku|1!!!211|dia|1";
$simpan_array = array();
$array_status = array();
// Pecah Array dari user dulu
$array_code_user = explode('!!!', $data1 );
$jumlah_item_user = count($array_code_user) - 1;
$x = 0;
// Pecah Array dari lokal
$array_cart_local = explode('!!!',$data2 );
$jumlah_cart_local = count($array_cart_local) - 1;
$j = 0;
while( $x <= $jumlah_item_user ) {
$ambil_datacart_user = explode( '|', $array_code_user[$x] );
$idproduk_user = $ambil_datacart_user[0];
$namaprod_user = $ambil_datacart_user[1];
$jumprod_user = $ambil_datacart_user[2];
$simpan_array_0 = $idproduk_user.'|'.$namaprod_user.'|'.$jumprod_user;
while( $j <= $jumlah_cart_local ) {
$ambil_datacart_lokal = explode( '|', $array_cart_local[$j] );
$idprod_lokal = $ambil_datacart_lokal[0];
$namaprod_lokal = $ambil_datacart_lokal[1];
$jumprod_lokal = $ambil_datacart_lokal[2];
$simpan_array_1 = $idprod_lokal.'|'.$namaprod_lokal.'|'.$jumprod_lokal;
//Disamakan
if( $idproduk_user == $idprod_lokal ) {
$jumtotal = $jumprod_user + $jumprod_lokal;
$simpan_array[] = $idprod_lokal.'|'.$namaprod_lokal.'|'.$jumtotal;
$array_status[] = 1;
} else {
$simpan_array[] = $simpan_array_1;
$array_status[] = 0;
}
$j++;
}
$x++;
}
$jumlah = array_sum($array_status);
$array_jadi = join("!!!",$simpan_array);
//$datakembali = $array_jadi;
if ( $jumlah == 0 ) {
$datakembali = $simpan_array_1.'!!!'.$array_jadi;
} else {
$datakembali = $array_jadi;
}
echo $datakembali;
?>
I loop the first array and call the output "result".
Then as I loop the second I see if the data exists in result array and it they do I add it to result else I create the new item.
$array1 = explode("!!!", $array1);
$array2 = explode("!!!", $array2);
Foreach($array1 as $val){
List($id, $name, $amount) = explode("|", $val);
$result[$id] = ['name' => $name, 'amount' => $amount];
}
Foreach($array2 as $val){
List($id, $name, $amount) = explode("|", $val);
If(isset($result[$id])){
$result[$id]['amount'] += $amount;
}Else{
$result[$id] = ['name' => $name, 'amount' => $amount];
}
}
https://3v4l.org/gQjTj
I did not include the conversion back to your format.
It's a cute format with all the pipes and exclamation marks but I strongly encourage you to use json_encode().
That makes a string that can easily be decoded again without home made functions.
See here https://3v4l.org/IEhsp
You can do something like:
$array1 = "144|aku|1!!!122|dia|2";
$array2 = "144|aku|1!!!211|dia|1";
//Convert the string into array by explode
$array1 = explode( '!!!', $array1 );
$array2 = explode( '!!!', $array2 );
//Merge the 2 arrays
$merged = array_merge($array1,$array2);
//Group the array using foreach
//Loop thru the array and group using the id as key
$grouped = array();
foreach( $merged as $key => $val ) {
$val = explode( '|', $val ); //Convert the string into array
if ( !isset( $grouped[ $val[0] ] ) ) $grouped[ $val[0] ] = $val; //If key does not exist, initialise the data
else $grouped[ $val[0] ][2] += $val[2]; //If key already exist, just add the third value
}
//Format the grouped array into string
foreach( $grouped as $key => $val ) {
$grouped[ $key ] = implode( '|', $val );
}
$result = implode( '!!!', $grouped );
echo $result;
This will result to:
144|aku|2!!!122|dia|2!!!211|dia|1
Related
I have an array that looks like this:
$ratingsInPosts = array
(
array("1",3),
array("2",5),
array("2",2),
array("5",2),
array("90",1),
array("5",6),
array("2",2),
);
I Want to find duplicate values in the first column and avarage its values from the second column.
So that this("1",3),("2",5),("2",2),("5",2),("90",1),("5",6),("2",2)
ends up like this ("1",3),("2",3),("5",4),("90",1)
Try this tested solution
I got the required Output
$ratingsInPosts = array
(
array("1",3),
array("2",5),
array("2",2),
array("5",2),
array("90",1),
array("5",6),
array("2",2),
);
$arr1 = array_column($ratingsInPosts, 0);
$p = array_count_values($arr1);
foreach($p as $key => $value)
{
$sum = 0;
for($i=0; $i < $value; $i++)
{
$pos = array_search($key, $arr1);
$sum += $ratingsInPosts[$pos][1];
unset($arr1[$pos]);
unset($ratingsInPosts[$pos]);
}
$re[] = array('"'.$key.'"',$sum/$value);
}
print_r($re);
I hope it helps you:
$groups = array();
// in this loop we group values by first column
foreach ($ratingsInPosts as $row) {
$key = $row[0];
if (!isset($groups[$key]) {
$groups[$key] = array();
}
$groups[$key][] = $row[1];
}
$result = array();
foreach ($groups as $key => $value) {
$avg = array_sum($value) / count($value);
$row = array($key, $avg);
$result[] = $row;
}
<?php
header('Content-Type: text/plain');
$ratingsInPosts = array(array("1",3),array("2",5),array("2",2),array("5",2),array("90",1),array("5",6),array("2",2));
$result = array();
$output = array();
foreach($ratingsInPosts as $array){
$result[$array[0]][] = $array[1];
}
foreach($result as $key=>$array){
$output[] = array($key,round(array_sum($array)/count($array)));
}
var_export($output);
?>
I've been struggling with this for a few days and wanted to throw it out there and see if someone has any ideas.
Basically I have a string e.g
1) "/0/bar"
2) "/build/0/foo/1"
and need to convert this into a multidimensional array
1) $result[0][bar]
2) $result[build][0][foo][1]
So far I've tried:
$query = "/build/0/foo/1";
$queryAr = [];
$current = &$queryAr;
$keys = explode("/", $query);
foreach($keys as $key) {
#$current = &$current[$key];
}
$current = $value;
quieting the output is a pretty hacky way to achive this...
You need to trim the first / of the string. live demo.
<?php
$query = "/build/0/foo/1";
$queryAr = [];
$current = &$queryAr;
$keys = explode("/", trim($query, '/'));
foreach($keys as $key) {
#$current = &$current[$key];
}
$current = $value;
print_r($queryAr);
I tried a recursive function version:
$query = "/build/0/foo/1";
print_r($result = buildNestedArray(explode('/', trim($query, '/'))));
function buildNestedArray($keys)
{
$k = current($keys);
$result = [$k => 'DONE'];
array_shift($keys);
if (sizeof($keys) > 0) { $result[$k] = buildNestedArray($keys); }
return $result;
}
output: Array ( [build] => Array ( [0] => Array ( [foo] => Array ( [1] => DONE ) ) ) )
I have a string like this:
$config = 'app.name = "My App";
app.id = "myappid";
app.components.cache.id = "Memcache";';
I need to convert it to array like this:
app=>[
'name=>'My App',
'id'=>'myappid',
'components'=>[
'cache'=>['id'=>'Memcache']
]
]
I use explode for divide on the pieces, but i don't know what i need to do next.
$arr = explode(";", $config);
$data = [];
foreach ($arr as $item) {
$pieces = explode('=', $item);
$pieces_dotes = explode('.', $pieces[0]);
foreach ($pieces_dotes as $piece) {
//what i need to do here?
}
}
How about this? Within the inner foreach loop, you're assigning the temp variable by reference to itself, so you build a stack of array keys, and then assign the value to it at the end.
$config = 'app.name = "My App";
app.id = "myappid";
app.components.cache.id = "Memcache";';
$arr = explode(";", $config);
$data = [];
foreach ($arr as $item) {
$temp = &$data;
$item = trim($item);
if (empty($item)) continue;
list($setting, $value) = explode("=", trim($item));
$setting = explode(".", trim($setting));
foreach ($setting as $set) {
$temp = &$temp[$set];
}
$temp = trim($value, '" ');
}
print_r($data);
This can be solved by building the array levels based on the key and keeping a reference to the last added level in the array. My solution (based on what you already had) is as follows:
<?php
$config = 'app.name = "My App";
app.id = "myappid";
app.components.cache.id = "Memcache";';
$arr = explode(";", $config);
$data = [];
foreach ($arr as $item) {
$pieces = explode('=', $item);
$currentValue = trim(str_replace('"', '', $pieces[1]));
$pieces_dotes = explode('.', $pieces[0]);
// Set initial value of $currentLevel to root of data array
$currentLevel = &$data;
// Initiate count & iterator vars
$numPieces = count($pieces_dotes);
$i = 0;
foreach ($pieces_dotes as $piece) {
// Increment $i and set $newKey to be trimmed version of current piece of the dot notated level
$i++;
$newKey = trim($piece);
// Skip empty $newKey
if(empty($newKey)) {
continue;
}
// Assign the $currentValue once we are at the required depth
if($i == $numPieces) {
$currentLevel[$newKey] = $currentValue;
}
// We are not at the required depth yet so initiate the key as an array if required
if(empty($currentLevel[$newKey])) {
$currentLevel[$newKey] = [];
}
// Set the $currentLevel to reference the new key
if(is_array($currentLevel[$newKey])) {
$currentLevel = &$currentLevel[$newKey];
}
}
}
Hope this helps!
The solution using custom recursive function fillBypath:
/**
* Fills an array by hierarchical 'key path'
*
* #param type $value value in each 'key path'
* #param type $keys hierarchical key list
* #param type $arr the resulting array(passed by reference)
*/
function fillByPath($value, $keys, &$arr) {
$c = count($keys) - 1;
foreach ($keys as $idx => $k) {
if ($idx == $c) { // check if it's the last key in the "key path"
$arr[$k] = $value;
break;
}
if (isset($arr[$k]) && is_array($arr[$k])) {
fillByPath($value, array_slice($keys, $idx + 1), $arr[$k]);
break;
} else {
$arr[$k] = [];
fillByPath($value, array_slice($keys, $idx + 1), $arr[$k]);
break;
}
}
}
$config = 'app.name = "My App";
app.id = "myappid";
app.components.cache.id = "Memcache";';
$result = [];
foreach (array_filter(explode(";", $config)) as $path) {
list($keyPath, $v) = explode(" = ", trim($path));
$keys = explode(".", $keyPath); // getting key list
fillByPath($v, $keys, $result);
}
print_r($result);
The output:
(
[app] => Array
(
[name] => "My App"
[id] => "myappid"
[components] => Array
(
[cache] => Array
(
[id] => "Memcache"
)
)
)
)
My intent is to take a series of strings, explode them by "_" and use the keys from that array to build a "master" array.
My rules are:
if key no exists -> create key under parent array
if key exists -> add key as new array to parent
if key is last -> add value
String Examples
total_players_count
total_rosters_count
players_season1_count
players_season2_count
rosters_season1_count
Expected Results
$main = array(
'total' => array(
'players' => array(
'count' => '123',
'rosters' => array(
'count' => '123')
)
),
'players' => array(
'season1' => array(
'count' => '123'
)
)
);
I hope this shows what I've expected to write. Now let me lead into how I disappointed myself through a series of failures last night ;)
The gist is, my recursive functions haven't been working so well so I'm not posting any of that code. I've been working with array_key_exists and that isn't getting me my expected results. I came close using prev(), current(), and end() but the issue stems from an unexpected number of keys I have to parse through (otherwise I would just loop 3 times and be done. I know the following would work if I had a limited amount of keys to parse; but I don't.
<?php
private function _get_section($parent_key, $sql) {
$data = array();
$data[$parent_key] = array();
foreach ($sql AS $key => $value) {
$keys = explode('_', $key);
if ($keys[0] == $parent_key) {
$i = 0;
$total_keys = count($keys);
for ($k = 1; $k < $total_keys; $k++) {
$i++;
if ($i == 1) {
echo '1. (' . $i . ') ' . $keys[$k];
$data[$parent_key][$keys[$k]] = array();
}
else if ($i > 1 && $i < $total_keys - 1) {
$data[$parent_key][$keys[$k - 1]][$keys[$k]] = array();
}
else if ($i == $total_keys - 1) {
$tmp = array_reverse($data);
// can't get the last key because I need to recursively loop
// through the results to find where to set this last
// key / value
}
}
$k = 0;
$i = 0;
}
$keys = array();
$total_keys = 0;
}
}
Solution (thank you)
$tree = array();
foreach ($sql AS $key => $value) {
$parts = explode('_', $key);
$val = $value;
foreach (array_reverse($parts) AS $part) {
$val = array($part => $val);
}
$tree = array_merge_recursive($tree, $val);
}
untested. hopefully i didnt need to read your code to fully understand what you want, because i didnt. i just looked at the expected results + the input, although i wonder what happened to rosters_season1_count?
$tree = array();
foreach ($strings as $string) {
$parts = explode('_', $string);
$path = '123';
foreach (array_reverse($parts) as $part) {
$path = array($part => $path);
}
$tree = array_merge_recursive($tree, $path);
}
Whats the easiest way to invert a multidimensional array. By invert I mean similar to array_flip.
e.g
[0][5][var_name] = data
[0][3][var_name2] = data2
[1][var_name3] = data3
[0][1][4][var_name4] = data4
inverted would be:
[var_name][0][5] = data
[var_name2][0][3] = data2
[var_name3][1] = data3
[var_name4][0][1][4] = data4
Any ideas?
You could store a list of the keys of all ancestors and when you hit a "leaf" use this list to create the "flipped" version.
<?php
$data = array(
0=>array(
5=>array('var_name' => 'data'),
3=>array('var_name2' => 'data2'),
1=>array(4=>array('var_name4'=>'data4'))
),
1=>array('var_name3'=>'data3')
);
$result = array();
foo($data, $result);
($result['var_name'][0][5] === 'data') or die('1');
($result['var_name2'][0][3] === 'data2') or die('2');
($result['var_name3'][1] === 'data3') or die('3');
($result['var_name4'][0][1][4] === 'data4') or die('4');
echo 'ok';
function foo(array $a, array &$target, $stack=array()) {
foreach($a as $key=>$value) {
if ( is_array($value) ) {
array_push($stack, $key);
foo($value, $target, $stack);
array_pop($stack);
}
else {
$target[$key] = array();
$tmp = &$target[$key];
foreach( $stack as $s ) { // now it's not so stack-ish anymore :-S
$tmp[$s] = array();
$tmp = &$tmp[$s];
}
$tmp = $value;
}
}
}
I couldn't think of an easy way to do this. So I wrote up a really complicated way to do it. Namely:
Take the multidimensional array and flatten it into a list of keys and values.
Reverse the keys.
Unflatten the list to obtain an inverted multidimensional array.
Code
<?php
function print_entries($array, $prekeys = array())
{
foreach ($array as $key => $value)
{
$keys = array_merge($prekeys, array($key));
if (is_array($value))
print_entries($value, $keys);
else
echo '[' . implode('][', $keys) . "] = $value\n";
}
}
function flatten_array($array)
{
$entries = array();
foreach ($array as $key => $value)
{
if (is_array($value))
{
foreach (flatten_array($value) as $subentry)
{
$subkeys = $subentry[0];
$subvalue = $subentry[1];
$entries[] = array(array_merge(array($key), $subkeys), $subvalue);
}
}
else
$entries[] = array(array($key), $value);
}
return $entries;
}
function unflatten_array($entries)
{
$array = array();
foreach ($entries as $entry)
{
$keys = $entry[0];
$value = $entry[1];
$subarray = &$array;
foreach ($keys as $i => $key)
{
if ($i < count($keys) - 1)
{
if (!isset($subarray[$key]))
$subarray[$key] = array();
$subarray = &$subarray[$key];
}
else
$subarray[$key] = $value;
}
}
return $array;
}
function invert_array($array)
{
$entries = flatten_array($array);
foreach ($entries as &$entry)
$entry[0] = array_reverse($entry[0]);
return unflatten_array($entries);
}
$array = array
(
0 => array
(
5 => array('var_name' => 'data'),
3 => array('var_name2' => 'data2'),
1 => array(4 => array('var_name4' => 'data4'))
),
1 => array(0 => array('var_name' => 'data3'))
);
print_entries($array);
echo "\n";
print_entries(invert_array($array));
?>
Output
[0][5][var_name] = data
[0][3][var_name2] = data2
[0][1][4][var_name4] = data4
[1][0][var_name] = data3
[var_name][5][0] = data
[var_name2][3][0] = data2
[var_name4][4][1][0] = data4
[var_name][0][1] = data3
Edit: I noticed now that you don't reverse the keys but you simply move the var_name portion from the end to the front and leave the numerical indices alone. It's easy enough to modify the line in flatten_array where I call array_reverse to re-order the keys in a different way. The core flatten/unflatten logic would not need to be changed. I leave this as an exercise for the reader. :-)