Conversion of an array from one form to another - php

I have an array.
Array
(
[0] => 1_4
[1] => 1_1
[2] => 1_2
[3] => 2_3
[4] => 2_5
)
I want to convert it to
Array
(
[1] => Array (4,1,2)
[2] => Array (3,5)
)
Can any1 help me in this? The new keys (1 and 2) are the distinct values from 1st part of array before _.

If the underscore will always be the unique split you could explode on underscore and append results to a new array.
$before = ['1_4','1_1','1_2','2_3','2_5'];
$after = [];
foreach ($before as $entry) {
$index = explode('_',$entry);
$after[$index[0]][] = $index[1];
}
return $after;

Quick and dirty...
foreach($array as $value){ // Loop your current array
$arr = substr($value,0); // Get the character before _, 1 or 2
$val = substr($value,2); // Get character after _, 1,2,3,4 or 5
if($arr == 1){ // if 1_, put into first new array
$newArray[0][] = $val;
}else{
$newArray[1][] = $val; // Put into second array else
}
}
print_r($newArray);

Maybe try something like this?
foreach ($array as $element( {
$kv_pair = explode("_", $element, 2);
if (array_key_exists($kv_pair[0])) {
array_push($new_array[$kv_pair[0]], $kv_pair[1]);
} else {
$new_array[$kv_pair[0]] = [$kv_pair[1]];
}
}

Related

Split flat array into grouped subarrays containing values from consecutive key in the input array

I have an array from array_diff function and it looks like below:
Array
(
[0] => world
[1] => is
[2] => a
[3] => wonderfull
[5] => in
[6] => our
)
As you can see, we have a gap between the keys #3 and #5 (i.e. there is no key #4).
How can I split that array into 2 parts, or maybe more if there are more gaps?
The expected output would be:
Array
(
[0] => Array
(
[0] => world
[1] => is
[2] => a
[3] => wonderfull
)
[1] => Array
(
[0] => in
[1] => our
)
)
You can use old_key,new_key concept to check that there difference is 1 or not? if not then create new index inside you result array otherwise add the values on same index:-
<?php
$arr = Array(0 => 'world',1 => 'is',2 => 'a',3 => 'wonderfull',5 => 'in',6 => 'our');
$new_array = [];
$old_key = -1;
$i = 0;
foreach($arr as $key=>$val){
if(($key-$old_key) ==1){
$new_array[$i][] = $val;
$old_key = $key;
}
if(($key-$old_key) >1){
$i++;
$new_array[$i][] = $val;
$old_key = $key;
}
}
print_r($new_array);
https://3v4l.org/Yl9rp
You can make use of the array internal pointer to traverse the array.
<?php
$arr = Array(0=>"world",1=>"is",2=>"a",3=>"wonderfull",5=>"in",6=>"our");
print_r($arr);
$result = Array();
$lastkey;
while($word = current($arr))
{
$key = key($arr);
if(isset($lastkey) && $key == $lastkey + 1)
{
$result[count($result) - 1][] = $word;
}
else
{
$result[] = Array($word);
}
$lastkey = $key;
next($arr);
}
print_r($result);
?>
This task is a perfect candidate for a reference variable. You unconditionally push values into a designated "bucket" -- in this case a subarray. You only conditionally change where that bucket is in the output array.
There are two important checks to make when determining if a new incremented key should be generated:
if it is not the first iteration and
the current key minus (the previous key + 1) does not equal 0.
Code: (Demo)
$nextKey = null;
$result = [];
foreach ($array as $key => $val) {
if ($nextKey === null || $key !== $nextKey) {
unset($ref);
$result[] = &$ref;
}
$ref[] = $val;
$nextKey = $key + 1;
}
var_export($result);
This solution generates an indexed array starting from zero with my sample input and uses only one if block. In contrast, AliveToDie's solution generates a numerically keyed array starting from 1 and uses two condition blocks containing redundant lines of code.

parse_str array return only last value

I am using ajax to submit the form and ajax value post as:
newcoach=6&newcoach=11&newcoach=12&newcoach=13&newcoach=14
In PHP I am using parse_str to convert string to array,but it return only last value:
$newcoach = "newcoach=6&newcoach=11&newcoach=12&newcoach=13&newcoach=14";
$searcharray = array();
parse_str($newcoach, $searcharray);
print_r($searcharray);
Result array having only last value:
Array
(
[newcoach] => 14
)
Any help will be appreciated...
Since you set your argument newcoach multiple times, parse_str will only return the last one. If you want parse_str to parse your variable as an array you need to supply it in this format with a '[ ]' suffix:
$newcoach = "newcoach[]=6&newcoach[]=11&newcoach[]=12&newcoach[]=13&newcoach[]=14";
Example:
<?php
$newcoach = "newcoach[]=6&newcoach[]=11&newcoach[]h=12&newcoach[]=13&newcoach[]=14";
$searcharray = array();
parse_str($newcoach, $searcharray);
print_r($searcharray);
?>
Outputs:
Array ( [newcoach] => Array ( [0] => 6 [1] => 11 [2] => 12 [3] => 13 [4] => 14 ) )
Currently it is assigning the last value as all parameter have same name.
You can use [] after variable name , it will create newcoach array with all values within it.
$test = "newcoach[]=6&newcoach[]=11&newcoach[]=12&newcoach[]=13&newcoach[]=14";
echo '<pre>';
parse_str($test,$result);
print_r($result);
O/p:
Array
(
[newcoach] => Array
(
[0] => 6
[1] => 11
[2] => 12
[3] => 13
[4] => 14
)
)
Use this function
function proper_parse_str($str) {
# result array
$arr = array();
# split on outer delimiter
$pairs = explode('&', $str);
# loop through each pair
foreach ($pairs as $i) {
# split into name and value
list($name,$value) = explode('=', $i, 2);
# if name already exists
if( isset($arr[$name]) ) {
# stick multiple values into an array
if( is_array($arr[$name]) ) {
$arr[$name][] = $value;
}
else {
$arr[$name] = array($arr[$name], $value);
}
}
# otherwise, simply stick it in a scalar
else {
$arr[$name] = $value;
}
}
# return result array
return $arr;
}
$parsed_array = proper_parse_str($newcoach);

Get specific content from a string

I need to get numbers as an array from a given string.
Example string:
$t = '1-P,2-T,3-P,4-R,5-C,6-T,';
Expected output:
if I search -T the output needs to be like this:
array(
[0] => 2,
[1] => 6
)
if it's -P:
array(
[0] => 1,
[1] => 3
)
I tried var_export(explode("-T,",$t)); but it didn't work as expected.
Can any one give me a suggestion to get this?
The below matches the full integer number which preceeds the search term -P.
Let's keep it concise:
$matches = array();
if (preg_match_all('/([0-9]+)\-P/', $t, $matches) >= 1) {
var_dump($matches[1]);
}
Search for '/([0-9]+)\-P/, '/([0-9]+)\-C/, '/([0-9]+)\-T/ an so on.
A more dynamic way to look for different search terms/filters:
$filter = '-T';
$pattern = sprintf('/([0-9]+)%s/', preg_quote($filter));
See preg_match_all and preg_quote functions.
Try this:
$t = '211111111131-P,2-T,3654554-P,4-R,5-C,6-T,';
$find = "-P"; // Search element
$found = []; // Result array
$array = explode(",", $t); // Breaking up into array
foreach($array as $arr) {
if (strpos($arr, $find)) { // Checking if search element is found in $arr
$found[] = explode('-',$arr)[0]; // Extracting the number prefix e.g 1 for 1-P
}
}
Output:
Array
(
[0] => 1
[1] => 3
)
Use it as
$t = '1-P,2-T,3-P,4-R,5-C,6-T,';
$data = explode(",", $t);
print_r($data);
$row=array();
for ($i = 0; $i <= count($data); $i++) {
if (!empty($data[$i])) {
if (strpos($data[$i], '-T') !== false) {// pass find value here
$final = explode("-", $data[$i]);
$row[]=$final[0];
}
}
}
print_r($row);
Output
Array
(
[0] => 2
[1] => 6
)
DEMO
$t = '1-P,2-T,3-P,4-R,5-C,6-T,';
$temp = [];
// if the last comma is not typo the 3rd argument `-1` omit empty item
$array = explode(",", $t, -1);
foreach($array as $arr) {
list($v, $k) = explode('-', $arr);
$temp[$k][] = $v;
}
print_r($temp['T']);
demo
Lots of good answers here already, but none take the approach of first putting the data into a better structure.
The code below converts the data to an associative array mapping letters to arrays of numbers, so that you can then do repeated lookups by whichever letter you want:
$t = '1-P,2-T,3-P,4-R,5-C,6-T,';
$a = array_filter(explode(',', $t));
$map = [];
foreach($a as $item) {
$exploded = explode('-', $item);
$number = $exploded[0];
$letter = $exploded[1];
if (!array_key_exists($letter, $map)) {
$map[$letter] = [];
}
$map[$letter][] = $number;
}
print_r($map);
// Array
// (
// [P] => Array
// (
// [0] => 1
// [1] => 3
// )
//
// [T] => Array
// (
// [0] => 2
// [1] => 6
// )
//
// [R] => Array
// (
// [0] => 4
// )
//
// [C] => Array
// (
// [0] => 5
// )
//
// )
print_r($map['T']);
// Array
// (
// [0] => 2
// [1] => 6
// )
print_r($map['P']);
// Array
// (
// [0] => 1
// [1] => 3
// )

Concat values of array with same key

I want to concat values of array with same key
Example:
[0] => Array
(
[0] => A
[1] => XYZ
)
[1] => Array
(
[0] => B
[1] => ABC
)
[2] => Array
(
[0] => A
[1] => LMN
)
[3] => Array
(
[0] => B
[1] => PQR
)
)
Expected output:
[0] => Array
(
[0] => A
[1] => XYZ,LMN
)
[1] => Array
(
[0] => B
[1] => ABC,PQR
)
)
A simple solution uses the PHP function array_reduce():
// The input array you posted in the question
$input = array(
array('A', 'XYZ'),
array('B', 'ABC'),
array('A', 'LMN'),
array('B', 'PQR'),
);
// Reduce the array to a new array that contains the data aggregated as you need
$output = array_reduce(
// Process each $item from $input using a callback function
$input,
// The callback function processes $item; the partial result is $carry
function (array $carry, array $item) {
// Extract the key into a variable
$key = $item[0];
// If the key was encountered before
// then a partial entry already exists in $carry
if (isset($carry[$key])) {
// Append the desired value to the existing entry
$carry[$key][1] .= ','.$item[1];
} else {
// Create a new entry in $carry (copy $item to key $key for quick retrieval)
$carry[$key] = $item;
}
// Return the updated $carry
return $carry;
},
// Start with an empty array (it is known as $carry in the callback function)
array()
);
// $output contains the array you need
Try this:
$final = array();
foreach ($array_items as $item)
{
$key = $item[0];
$found_index = -1;
for ($i=0; $i<count($final); $i++)
{
if ($key == $final[$i][0])
{
$found_index = $i;
break;
}
}
if ($found_index == -1)
{
$final_item = array();
$final_item[0] = $key;
$final_item[1] = $item[1];
$final[] = $final_item;
}
else
{
$final[$found_index][1] .= ",".$item[1];
}
}
We create a new array $final, and loop through your old array $array_items. For each item, we see if there is already an item in $final that has the same [0] index. If it doesn't exist, we create it and add the initial string to the [1] index. If it does exist, we just have to add the string onto the end of the [1] index.
Try it, substituting $array_items for whatever your array is called, let me know if it works.
Check my solution. It should work fine. I hope it will help you much.
$result = $passed_keys = $extended_arr = [];
foreach ($arr as $k => $value) {
for($i = $k + 1; $i < count($arr); $i++){
if ( $value[0] == $arr[$i][0] ){ // compare each array with rest subsequent arrays
$key_name = $value[0];
if (!array_key_exists($key_name, $result)){
$result[$key_name] = $value[1] .",". $arr[$i][1];
} else {
if (!in_array($i, $passed_keys[$key_name])) {
$result[$key_name] .= ",". $arr[$i][1];
}
}
$passed_keys[$key_name][] = $i; // memorizing keys that were passed
}
}
}
array_walk($result, function($v, $k) use(&$extended_arr){
$extended_arr[] = [$k, $v];
});
The result is in $extended_arr
My solution, creates a custom key which makes identifying the letter much easier. This removes the need to continuously iterate through each array, which can become a major resources hog.
<?php
$inital_array = array(
array('A','XYZ'),
array('B','ABC'),
array('A','LMN'),
array('B','PQR')
);
$concat_array = array();
foreach($inital_array as $a){
$key = $a[0];
if( !isset($concat_array[$key]) ){
$concat_array[$key] = array($key,'');
}
$concat_array[$key][1] .= (empty($concat_array[$key][1]) ? '' : ',').$a[1];
}
$concat_array = array_values($concat_array);
echo '<pre>',print_r($concat_array),'</pre>';

php multidimensional array from known key values

I have a collection of keys in this massive flat single array I would like to basically expand that array into a multidimensional one organized by keys - here is an example:
'invoice/products/data/item1'
'invoice/products/data/item2'
'invoice/products/data/item2'
=>
'invoice'=>'products'=>array('item1','item2','item3')
how can I do this - the length of the above strings are variable...
Thanks!
$src = array(
'invoice/products/data/item1',
'invoice/products/data/item2',
'invoice/products/data/item2',
'foo/bar/baz',
'aaa/bbb'
);
function rsplit(&$v, $w)
{
list($first, $tail) = explode('/', $w, 2);
if(empty($tail))
{
$v[] = $first;
return $v;
}
$v[$first] = rsplit($v[$first], $tail);
return $v;
}
$result = array_reduce($src, "rsplit");
print_r($result);
Output is:
Array (
[invoice] => Array
(
[products] => Array
(
[data] => Array
(
[0] => item1
[1] => item2
[2] => item2
)
)
)
[foo] => Array
(
[bar] => Array
(
[0] => baz
)
)
[aaa] => Array
(
[0] => bbb
)
)
Something along these lines: (Didn't test it though!) Works now ;)
$data = array();
$current = &$data;
foreach($keys as $value) {
$parts = explode("/", $value);
$parts_count = count($parts);
foreach($parts as $i => $part) {
if(!array_key_exists($part, $current)) {
if($i == $parts_count - 1) {
$current[] = $part;
}
else {
$current[$part] = array();
$current = &$current[$part];
}
}
else {
$current = &$current[$part];
}
}
$current = &$data;
}
$keys beeing the flat array.
Although it's not clear from your question how the "/" separated strings will map to an array, the basic approach will probably be something like this:
$result = array();
$k1 = $k2 = '';
ksort($yourData); // This is the key (!)
foreach ($yourData as $k => $v) {
// Use if / else if / else if to watch for new sub arrays and change
// $k1, $k2 accordingly
$result[$k1][$k2] = $v;
}
This approach uses the ksort to ensure that keys at the same "level" appear together, like this:
'invoice/products/data1/item1'
'invoice/products/data1/item2'
'invoice/products/data2/item3'
'invoice/products2/data3/item4'
'invoice/products2/data3/item5'
Notice how the ksort corresponds to the key grouping you're aiming for.

Categories