PHP Array split string and Integers - php

Below is an array of strings and numbers. How could the string and number values be split into separate arrays (with strings in one array and numbers in another array)?
array('a','b','c',1,2,3,4,5,'t','x','w')

You could also do this in one line using array_filter()
$numbers = array_filter($arr,function($e){return is_numeric($e);});
$alphas = array_filter($arr,function($e){return !is_numeric($e);});
print_r($numbers);
print_r($alphas);

Loop through them, check if is_numeric and add to appropriate array:
$original = array('a','b','c',1,2,3,4,5,'t','x','w');
$letters = array();
$numbers = array();
foreach($original as $element){
if(is_numeric($element)){
$numbers[] = $element;
}else{
$letters[] = $element;
}
}
https://3v4l.org/CAvVp

Using a foreach() like in #jnko's answer will be most performant because it only iterates over the array one time.
However, if you are not concerned with micro-optimization and prefer to write concise or functional-style code, then I recommend using array_filter() with is_numeric() calls, then making key comparisons between the first result and the original array.
Code: (Demo)
$array = ['a','b',0,'c',1,2,'ee',3,4,5,'t','x','w'];
$numbers = array_filter($array, 'is_numeric');
var_export($numbers);
var_export(array_diff_key($array, $numbers));
Output:
array (
2 => 0,
4 => 1,
5 => 2,
7 => 3,
8 => 4,
9 => 5,
)
array (
0 => 'a',
1 => 'b',
3 => 'c',
6 => 'ee',
10 => 't',
11 => 'x',
12 => 'w',
)

$data = array('a','b','c',1,2,3,4,5,'t','x','w');
$integerArray = array();
$stringArray = array();
$undefinedArray = array();
foreach($data as $temp)
{
if(gettype($temp) == "integer")
{
array_push($integerArray,$temp);
}elseif(gettype($temp) == "string"){
array_push($stringArray,$temp);
}else{
array_push($undefinedArray,$temp);
}
}

Related

exploding string with multiple delimiter [duplicate]

This question already has answers here:
PHP - split String in Key/Value pairs
(5 answers)
Convert backslash-delimited string into an associative array
(4 answers)
Closed 12 months ago.
i have a string like
$str = "1-a,2-b,3-c";
i want to convert it into a single array like this
$array = [
1 => "a",
2 => "b",
3 => "c"
];
what i do is
$str = "1-a,2-b,3-c";
$array = [];
$strex = explode(",", $str);
foreach ($strex as $str2) {
$alphanumeric = explode("-", $str2);
$array[$alphanumeric[0]] = $alphanumeric[1];
}
can i do this in a better way?
You can use preg_match_all for this:
<?php
$str = "1-a,2-b,3-c";
preg_match_all('/[0-9]/', $str, $keys);
preg_match_all('/[a-zA-Z]/', $str, $values);
$new = array_combine($keys[0], $values[0]);
echo '<pre>'. print_r($new, 1) .'</pre>';
here we take your string, explode() it and then preg_match_all the $value using patterns:
/[0-9]/ -> numeric value
/[a-zA-Z]/ -> letter
then use array_combine to get it into one array
Thanks to u_mulder, can shorten this further:
<?php
$str = "1-a,2-b,3-c";
preg_match_all('/(\d+)\-([a-z]+)/', $str, $matches);
$new = array_combine($matches[1], $matches[2]);
echo '<pre>'. print_r($new, 1) .'</pre>';
just a little benchmark:
5000 iterations
Debian stretch, php 7.3
parsed string: "1-a,2-b,3-c,4-d,5-e,6-f,7-g,8-h,9-i"
[edit] Updated with the last 2 proposals [/edit]
You can use preg_split with array_filter and array_combine,
function odd($var)
{
// returns whether the input integer is odd
return $var & 1;
}
function even($var)
{
// returns whether the input integer is even
return !($var & 1);
}
$str = "1-a,2-b,3-c";
$temp = preg_split("/(-|,)/", $str); // spliting with - and , as said multiple delim
$result =array_combine(array_filter($temp, "even", ARRAY_FILTER_USE_KEY),
array_filter($temp, "odd",ARRAY_FILTER_USE_KEY));
print_r($result);
array_filter — Filters elements of an array using a callback function
Note:- ARRAY_FILTER_USE_KEY - pass key as the only argument to callback instead of the value
array_combine — Creates an array by using one array for keys and another for its values
Demo
Output:-
Array
(
[1] => a
[2] => b
[3] => c
)
One way to do with array_map(),
<?php
$my_string = '1-a,2-b,3-c';
$my_array = array_map(function($val) {list($key,$value) = explode('-', $val); return [$key=>$value];}, explode(',', $my_string));
foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($my_array)) as $k=>$v){
$result[$k]=$v;
}
print_r($result);
?>
WORKING DEMO: https://3v4l.org/aYmOH
Tokens all the way down...
<?php
$str = '1-a,2-b,3-c';
$token = '-,';
if($n = strtok($str, $token))
$array[$n] = strtok($token);
while($n = strtok($token))
$array[$n] = strtok($token);
var_export($array);
Output:
array (
1 => 'a',
2 => 'b',
3 => 'c',
)
Or perhaps more terse without the first if...:
$array = [];
while($n = $array ? strtok($token) : strtok($str, $token))
$array[$n] = strtok($token);
Not a better way but one more example:
$str = "1-a,2-b,3-c";
$arr1 = explode(",", preg_replace("/\-([a-zA-Z]+)/", "", $str));
$arr2 = explode(",", preg_replace("/([0-9]+)\-/", "", $str));
print_r(array_combine($arr1, $arr2));
Mandatory one-liner (your mileage may vary):
<?php
parse_str(str_replace([',', '-'], ['&', '='], '1-a,2-b,3-c'), $output);
var_export($output);
Output:
array (
1 => 'a',
2 => 'b',
3 => 'c',
)
You can do one split on both the , and -, and then iterate through picking off every other pair ($k&1 is a check for an odd index):
<?php
$str = '1-a,2-b,3-c';
foreach(preg_split('/[,-]/', $str) as $k=>$v) {
$k&1 && $output[$last] = $v;
$last = $v;
}
var_export($output);
Output:
array (
1 => 'a',
2 => 'b',
3 => 'c',
)
The preg_split array looks like this:
array (
0 => '1',
1 => 'a',
2 => '2',
3 => 'b',
4 => '3',
5 => 'c',
)
This one explodes the string as the OP has on the comma, forming the pairs: (1-a) and (2-b) etc. and then explodes those pairs. Finally array_column is used to create the associated array:
<?php
$str = '1-a,2-b,3-c';
$output =
array_column(
array_map(
function($str) { return explode('-', $str); },
explode(',', $str)
),
1,
0
);
var_export($output);
Output:
array (
1 => 'a',
2 => 'b',
3 => 'c',
)

multidimensional array to one dimensional array recursively

I have this multidimensional array
$liste = [[1,2,3],5,[['x','y','z'],true]];
and I want to change it to one dimensionel array
$liste = [1,2,3,5,'x','y','z',true];
so i always have a problem that give me the same shape
function to_array($list){
$out=[];
if(!is_array($list)){
return $list;
}else{
foreach($list as $line){
$out[]= to_array($line);
}
}
return $out;
}
where is the problem in this recursive function !!!
The issue with your code is that you are pushing the result of to_array into $out, when what you want to do is use array_merge. Now since that requires both parameters to be arrays, when $list is not an array, you need to return an array containing the individual value. So change these lines:
return $list;
$out[]= to_array($line);
To:
return array($list);
$out = array_merge(to_array($line));
i.e.
function to_array($list){
$out=[];
if(!is_array($list)){
return array($list);
}else{
foreach($list as $line){
$out = array_merge($out, to_array($line));
}
}
return $out;
}
And you will get the result that you want:
var_export(to_array($liste));
Output:
array (
0 => 1,
1 => 2,
2 => 3,
3 => 5,
4 => 'x',
5 => 'y',
6 => 'z',
7 => true,
)
array_walk_recursive() delivers the desired result from an array of indeterminate depth in a one-liner because it only visits the "leaf-nodes" -- effectively, you don't need to bother checking if an element is or is not an array.
array_walk_recursive() doesn't return an array, it returns true|false based on whether or not there was a failure.
&$flat is a variable which is "passed by reference". This means that $flat can act as a vehicle to transport the data from inside the function scope to outside the function scope. As the elements are traversed, each new value is pushed into $flat using square bracket syntax.
This is exactly what this function does best -- use it.
Code: (Demo)
$liste = [[1, 2, 3], 5, [['x', 'y', 'z'], true]];
array_walk_recursive($liste, function($v) use (&$flat){ $flat[] = $v; });
var_export($flat);
Output:
array (
0 => 1,
1 => 2,
2 => 3,
3 => 5,
4 => 'x',
5 => 'y',
6 => 'z',
7 => true,
)

Compare two integer and count matching numbers

I have two integers for example "12345" and "98754", they have a count of 2 matching numbers
namely 4 and 5, the order doesnt matter.
Now: How do I check something like that in PHP?
You can split the inputs to arrays and use array_intersect to find matching numbers.
$a = 12345;
$b = 98754;
//Create arrays of the numbers
$a = str_split($a);
$b = str_split($b);
// Find matching numbers
$matching = array_intersect($a, $b);
Var_dump($matching);
// Output: 4,5
Echo count($matching);
// Output: 2
https://3v4l.org/8tS3q
Convert the numbers in to strings
create a loop from 0-9 to check for the appearance of a number in both strings using strstr() or similar
store the number in an array if it appears in both
Edit:
Code-centric solution:
$a = 1231534;
$b = 89058430;
$matches = compare( $a, $b );
print count($matches);
function compare ( $a, $b ) {
$str_a = (string) $a;
$str_b = (string) $b;
$matches = [];
for($i=0;$i<=9;$i++) {
if (strstr($str_a, (string)$i) && strstr($str_b,(string)$i)) $matches[] = $i;
}
return $matches;
}
Added an example here that counts digits that occur in both numbers.
If multiple digits occur in both, these are included:
<?php
function digits_in_both($x, $y)
{
$in_both = [];
$split_y = str_split($y);
foreach(str_split($x) as $n) {
$key = array_search($n, $split_y);
if($key !== false) {
$in_both[] = $n;
unset($split_y[$key]);
}
}
return $in_both;
}
$in_both = digits_in_both(123445, 4456);
var_export($in_both);
var_dump(count($in_both));
Output:
array (
0 => '4',
1 => '4',
2 => '5',
)int(3)
Contrary to what you expect with array_intersect, order matters as demonstrated here:
var_export(array_intersect(str_split('024688'), str_split('248')));
var_export(array_intersect(str_split('248'), str_split('024688')));
Output:
array (
1 => '2',
2 => '4',
4 => '8',
5 => '8',
)array (
0 => '2',
1 => '4',
2 => '8',
)

PHP Dynamically accessing an associative array

EDITED FROM ORIGINAL THAT HAD IMPLIED ONLY 1 ACCESS
If I have an array that contains x number of arrays, each of the form
array('country' => array('city' => array('postcode' => value)))
and another array that might be
array('country', 'city', 'postcode') or array('country', 'city')
depending on what I need to retrieve, how do I use the second array to identify the index levels into the first array and then access it.
By nesting references with $cur = &$cur[$v]; you can read and modify the original value:
Live example on ide1: http://ideone.com/xtmrr8
$array = array('x' => array('y' => array('z' => 20)));
$keys = array('x', 'y', 'z');
// Start nesting new keys
$cur = &$array;
foreach($keys as $v){
$cur = &$cur[$v];
}
echo $cur; // prints 20
$cur = 30; // modify $array['x']['y']['z']
Loop through the array of indexes, traveling down the initial array step by step until you reach the end of the index array.
$array1 = array('x' => array('y' => array('z' => 20)));
$keys = array('x', 'y', 'z');
$array_data = &$array1;
foreach($keys as $key){
$array_data = &$array_data[$key];
}
echo $array_data;
Ok, I apologize for not having expressed my question more clearly, originally, but I got it to work as I was hoping, with a variable variable, as follows:
$keystring = '';
foreach ($keys as $key) {
$keystring .= "['$key']";
}
Then iterate the main array, for each of the country entries in it, and access the desired value as:
eval('$value = $entry' . "$keystring;");

Transpose and flatten two-dimensional indexed array where rows may not be of equal length

I would like to take an array like this and combine it into 1 single array.
array (size=2)
0 =>
array (size=10)
0 => string '1'
1 => string 'a'
2 => string '3'
3 => string 'c'
1 =>
array (size=5)
0 => string '2'
1 => string 'b'
However I want the array results to be interleaved.
So it would end up looking like
array
0 => '1'
1 => '2'
2 => 'a'
3 => 'b'
4 => '3'
5 => 'c'
I would like it so that it doesn't matter how many initial keys are passed in (this one has 2), it should work with 1, 2 or 5. Also, as you can see from my example the amount of elements most likely won't match.
Anyone know the best way to accomplish this?
$data = array(
0 => array(
0 => '1',
1 => 'a',
2 => '3',
3 => 'c',
),
1 => array(
0 => '2',
1 => 'b',
),
);
$newArray = array();
$mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY);
$mi->attachIterator(new ArrayIterator($data[0]));
$mi->attachIterator(new ArrayIterator($data[1]));
foreach($mi as $details) {
$newArray = array_merge(
$newArray,
array_filter($details)
);
}
var_dump($newArray);
I had fun with this... So if you like it use it!
$arr1 = [1,'a',3,'c'];
$arr2 = ['2','b'];
$finarry = arrayInterweave($arr1,$arr2);
print_r($finarry);
function arrayInterweave($arr1,$arr2){
$count1 = count($arr1);
$count2 = count($arr2);
$length = (($count1 >= $count2) ? $count1 : $count2);
$fin = array();
for($i = 0;$i<$length;$i++){
if(!empty($arr1[$i])){
$fin[] = $arr1[$i];
}
if(!empty($arr2[$i])){
$fin[] = $arr2[$i];
}
}
return $fin;
}
Tried to think of a fun solution:
$array = [
["a","b","c"],
["d","e"]
];
$result = [];
while($array) {
array_walk(
$array,
function(&$subarray, $key) use (&$array, &$result) {
$result[] = array_shift($subarray);
if(empty($subarray)) unset ($array[$key]);
}
);
}
var_dump($result);
It destroys the original array though.
After determining which row contains the most elements, you can loop through known indexes and push columns of data into the result array.
The following technique is safe to use with a variable number of rows.
Code: (Demo)
$maxCount = max(array_map('count', $array));
$result = [];
for ($i = 0; $i < $maxCount; ++$i) {
array_push($result, ...array_column($array, $i));
}
var_export($result);
Input/Output:
$array
$result
[['b', 'e', 'd', 's'], ['l', 'n']]
['b', 'l', 'e', 'n', 'd', 's']
['f', 'g', 'n', 's'], ['r', 'm'], ['a', 'e', 't']
['f', 'r', 'a', 'g', 'm', 'e', 'n', 't' 's']
The above technique is perfectly capable of accommodating 3 or more input arrays as well.
p.s. For anyone running into technical limitations because their php version, this will do the same:
$maxCount = max(array_map('count', $array));
$result = [];
for ($i = 0; $i < $maxCount; ++$i) {
foreach (array_column($array, $i) as $found) {
$result[] = $found;
}
}
...if your php version doesn't accommodate the above snippet, you really, really need to upgrade your php version (sorry, not sorry).
To avoid the counting to determine the longest subarray, you can instead transpose the data with nested loops then flatten that result structure. (Demo)
$result = [];
foreach ($array as $i => $row) {
foreach ($row as $k => $v) {
$result[$k][$i] = $v;
}
}
var_export(array_merge(...$result));

Categories