I would post the entire code, but it is lengthly and confusing, so I'll keep it short and simple. This is complicated for myself, so any help will be greatly appreciated!
These are the values from my Array:
Light Blue1
Blue2
Blue1
Black3
Black2
Black1
The values I need to retrieve from my Array are "Light Blue1", "Blue2" and "Black3". These are the "highest values" for each color.
Something similar to what I'm looking for is array_unique, but that wouldn't work here. So something along those lines that can retrieve each color with its highest number.
Thanks!
Assuming your format is always NameNumber a regex should do the trick for separating the data. This will loop through your data in the order your provide and grab the first element that is different and put it into $vals. I am also assuming your data will always be ordered as your example shows
$data = ['Light Blue1',
'Blue2',
'Blue1',
'Black3',
'Black2',
'Black1'];
$vals = [];
$current = '';
foreach($data as $row) {
if(!preg_match('/(.*)(\d)/i', $row, $matched)) continue;
if($matched[1] != $current) {
$vals[] = $row;
$current = $matched[1];
}
}
The solution using preg_split and max functions:
$colors = ['Light Blue1', 'Blue2', 'Blue1', 'Black3', 'Black2', 'Black1'];
$unique_colors = $result = [];
foreach ($colors as $k => $v) {
$parts = preg_split("/(\d+)/", $v, 0, PREG_SPLIT_DELIM_CAPTURE);
$unique_colors[$parts[0]][] = (int) $parts[1];
}
foreach ($unique_colors as $k => $v) {
$result[] = $k . max($v);
}
print_r($result);
The output:
Array
(
[0] => Light Blue1
[1] => Blue2
[2] => Black3
)
If you pre-sort your array with "natural sorting", then you can loop through the array and unconditionally push values into the result with digitally-trimmed keys. This will effectively overwrite color entries with lesser number values and only store the the highest numbered color when the loop finishes.
Code: (Demo)
natsort($data);
$result = [];
foreach ($data as $value) {
$result[rtrim($value, '0..9')] = $value;
}
var_export(array_values($result));
Or you could parse each string and compare the number against its cached number (if encountered before): (Demo)
$result = [];
foreach ($data as $value) {
sscanf($value, '%[^0-9]%d', $color, $number);
if (!isset($result[$color]) || $result[$color]['number'] < $number) {
$result[$color] = ['value' => $value, 'number' => $number];
}
}
var_export(array_column($result, 'value'));
A related technique to find the highest value in a group
Related
I have strings in following format:
$strings[1] = cat:others;id:4,9,13
$strings[2] = id:4,9,13;cat:electric-products
$strings[3] = id:4,9,13;cat:foods;
$strings[4] = cat:drinks,foods;
where cat means category and id is identity number of a product.
I want to split these strings and convert into arrays $cats = array('others'); and $ids = array('4','9','13');
I know that it can be done by foreach and explode function through multiple steps. I think I am somewhere near, but the following code does not work.
Also, I wonder if it can be done by preg_match or preg_split in fewer steps. Or any other simpler method.
foreach ($strings as $key=>$string) {
$temps = explode(';', $string);
foreach($temps as $temp) {
$tempnest = explode(':', $temp);
$array[$tempnest[0]] .= explode(',', $tempnest[1]);
}
}
My desired result should be:
$cats = ['others', 'electric-products', 'foods', 'drinks';
and
$ids = ['4','9','13'];
One option could be doing a string compare for the first item after explode for cat and id to set the values to the right array.
$strings = ["cat:others;id:4,9,13", "id:4,9,13;cat:electric-products", "id:4,9,13;cat:foods", "cat:drinks,foods"];
foreach ($strings as $key=>$string) {
$temps = explode(';', $string);
$cats = [];
$ids = [];
foreach ($temps as $temp) {
$tempnest = explode(':', $temp);
if ($tempnest[0] === "cat") {
$cats = explode(',', $tempnest[1]);
}
if ($tempnest[0] === "id") {
$ids = explode(',', $tempnest[1]);
}
}
print_r($cats);
print_r($ids);
}
Php demo
Output for the first item would for example look like
Array
(
[0] => others
)
Array
(
[0] => 4
[1] => 9
[2] => 13
)
If you want to aggregate all the values in 2 arrays, you can array_merge the results, and at the end get the unique values using array_unique.
$strings = ["cat:others;id:4,9,13", "id:4,9,13;cat:electric-products", "id:4,9,13;cat:foods", "cat:drinks,foods"];
$cats = [];
$ids = [];
foreach ($strings as $key=>$string) {
$temps = explode(';', $string);
foreach ($temps as $temp) {
$tempnest = explode(':', $temp);
if ($tempnest[0] === "cat") {
$cats = array_merge(explode(',', $tempnest[1]), $cats);
}
if ($tempnest[0] === "id") {
$ids = array_merge(explode(',', $tempnest[1]), $ids);
}
}
}
print_r(array_unique($cats));
print_r(array_unique($ids));
Output
Array
(
[0] => drinks
[1] => foods
[3] => electric-products
[4] => others
)
Array
(
[0] => 4
[1] => 9
[2] => 13
)
Php demo
I don't generally recommend using variable variables, but you are looking for a sleek snippet which uses regex to avoid multiple explode() calls.
Here is a script that will use no explode() calls and no nested foreach() loops.
You can see how the \G ("continue" metacharacter) allows continuous matches relative the "bucket" label (id or cat) by calling var_export($matches);.
If this were my own code, I'd probably not create separate variables, but a single array containing id and cat --- this would alleviate the need for variable variables.
By using the encountered value as the key for the element to be added to the bucket, you are assured to have no duplicate values in any bucket -- just call array_values() if you want to re-index the bucket elements.
Code: (Demo) (Regex101)
$count = preg_match_all(
'/(?:^|;)(id|cat):|\G(?!^),?([^,;]+)/',
implode(';', $strings),
$matches,
PREG_UNMATCHED_AS_NULL
);
$cat = [];
$id = [];
for ($i = 0; $i < $count; ++$i) {
if ($matches[1][$i] !== null) {
$arrayName = $matches[1][$i];
} else {
${$arrayName}[$matches[2][$i]] = $matches[2][$i];
}
}
var_export(array_values($id));
echo "\n---\n";
var_export(array_values($cat));
All that said, I probably wouldn't rely on regex because it isn't very readable to the novice regex developer. The required logic is much simpler and easier to maintain with nested loops and explosions. Here is my adjustment of your code.
Code: (Demo)
$result = ['id' => [], 'cat' => []];
foreach ($strings as $string) {
foreach (explode(';', $string) as $segment) {
[$key, $values] = explode(':', $segment, 2);
array_push($result[$key], ...explode(',', $values));
}
}
var_export(array_unique($result['id']));
echo "\n---\n";
var_export(array_unique($result['cat']));
P.s. your posted coding attempt was using a combined operator .= (assignment & concatenation) instead of the more appropriate combined operator += (assignment & array union).
I have a little problem in my project : I would like display only the key of each array when I click on a element of my list. Dump of my table
For example when I click in "Paupiette", I would like display 0.
I partially succeeded but when I click in a element, I see only the last key (here "1").
Here,you can see the code
$carts = $cartService->getCart($user);
//dump($carts); die;
$mykey = 0;
foreach($carts as $key => $value) {
$mykey = $key;
}
dump($mykey);die;
If you have any idea, thank you a lot
You have multiple choice to display your $keys
the first one is :
$keys = array_keys($carts);
The second is :
foreach ($carts as $key => $value) {
dump($key);
}
if you will display all keys after loop
$myKeys = array();
foreach($carts as $key => $value) {
$myKeys[] = $key;
}
dump($myKeys);die;
If you just want to display the keys, following your coding "style":
foreach ($carts as $key => $value) {
dump($key);
}
If you want to display the keys as comma-separated string, again following your coding "style":
$keys = array_keys($carts); // Get the keys, eg, [0, 1];
$str = implode(', ', $keys); // Convert the array to string, eg, "0, 1"
dump($str);
I have two arrays:
$array_one = array('AA','BB','CC');
And:
$replacement_keys = array
(
""=>null,
"BFC"=>'john',
"ASD"=>'sara',
"CSD"=>'garry'
);
So far I've tried
array_combine and to make a loop and try to search for values but can't really find a solution to match the keys of the second array with the values of the first one and replace it.
My goal is to make a final output:
$new_array = array
(
''=>null,
'BB' => 'john',
'AA' => 'sara',
'CC' => 'garry'
);
In other words to find a matching first letter and than replace the key with the value of the first array.
Any and all help will be highly appreciated.
Here is a solution keeping both $replacement_keys and $array_one intact
$tempArray = array_map(function($value){return substr($value,0,1);}, $array_one);
//we will get an array with only the first characters
$new_array = [];
foreach($replacement_keys as $key => $replacement_key) {
$index = array_search(substr($key, 0, 1), $tempArray);
if ($index !== false) {
$new_array[$array_one[$index]] = $replacement_key;
} else {
$new_array[$key] = $replacement_key;
}
}
Here is a link https://3v4l.org/fuHSu
You can approach like this by using foreach with in_array
$a1 = array('AA','BB','CC');
$a2 = array(""=>null,"BFC"=>'john',"ASD"=>'sara',"CSD"=>'garry');
$r = [];
foreach($a2 as $k => $v){
$split = str_split($k)[0];
$split .= $split;
in_array($split, $a1) ? ($r[$split] = $v) : ($r[$k] = $v);
}
Working example :- https://3v4l.org/ffRWY
How can I get the list of values from my array:
[data] => Array
(
[5] => Array
(
[0] => 19
[1] => 18
[2] => 20
)
[6] => Array
(
[0] => 28
)
)
Expected output result string will be: 19,18,20,28
Thanks!
With one line, no loop.
echo implode(',', call_user_func_array('array_merge', $data));
Try it here.
Use following php code:
$temp = array();
foreach($data as $k=>$v){
if(is_array($v)){
foreach($v as $key=>$value){
$temp[] = $value;
}
}
}
echo implode(',',$temp);
Use following code.
$string = '';
foreach($yourarray as $k){
foreach($k as $l){
$string. = $l.",";
}
}
Just loop over sub arrays. Store values to $result array and then implode with ,
$result = array();
foreach ($data as $subArray) {
foreach ($subArray as $value) {
$result[] = $value;
}
}
echo implode(',', $result);
$data = array(5 => array(19,18,20), 6 => array(28));
foreach ($data as $array) {
foreach ($array as $array1) {
echo $array1.'<br>';
}
}
Try this one. It will help you
Since all of the data that you wish to target are "leaf nodes", array_walk_recursive() is a handy function to call.
Code: (Demo)
$data=[5=>[19,18,20],6=>[28]];
array_walk_recursive($data,function($v){static $first; echo $first.$v; $first=',';});
Output:
19,18,20,28
This method uses a static declaration to avoid the implode call and just iterates the call of echo with preceding commas after the first iteration. (no temporary array generated)
I haven't really taken the time to consider any fringe cases, but this is an unorthodox method that will directly provide the desired output string without loops or even generating a new, temporary array. It's a tidy little one-liner with a bit of regex magic. (Regex Demo) It effectively removes all square & curly brackets and double-quoted keys with trailing colons.
Code: (Demo)
$data=[5=>[19,18,20],6=>[28]];
echo preg_replace('/[{}[\]]+|"\d+":/','',json_encode($data));
Output:
19,18,20,28
To be clear/honest, this is a bit of hacky solution, but I think it is good for SO researchers to see that there are often multiple ways to achieve any given outcome.
try with this..
foreach($data as $dataArr){
foreach ($subArray as $value) {
$res[] = $value;
}
}
echo implode(',', $res);
Just use nested foreach Statements
$values = array();
foreach($dataArray as $key => $subDataArray) {
foreach($subDataArray as $value) {
$values[] = $value;
}
}
$valueString = implode(',', $values);
Edit: Added full solution..
Excuse me if this question was already solved. I've searched trough the site and couldn't find an answer.
I'm trying to build a bi-dimensional array from a string. The string has this structure:
$workers="name1:age1/name2:age2/name3:age3"
The idea is to explode the array into "persons" using "/" as separator, and then using ":" to explode each "person" into an array that would contain "name" and "age".
I know the basics about the explode function:
$array=explode("separator","$string");
But I have no idea how to face this to make it bidimensional. Any help would be appreciated.
Something like the following should work. The goal is to first split the data into smaller chunks, and then step through each chunk and further subdivide it as needed.
$row = 0;
foreach (explode("/", $workers) as $substring) {
$col = 0;
foreach (explode(":", $substring) as $value) {
$array[$row][$col] = $value;
$col++;
}
$row++;
}
$array = array();
$workers = explode('/', "name1:age1/name2:age2/name3:age3");
foreach ($workers as $worker) {
$worker = explode(':', $worker);
$array[$worker[0]] = $worker[1];
}
Try this code:
<?php
$new_arr=array();
$workers="name1:age1/name2:age2/name3:age3";
$arr=explode('/',$workers);
foreach($arr as $value){
$new_arr[]=explode(':',$value);
}
?>
The quick solution is
$results = [];
$data = explode("/", $workers);
foreach ($data as $row) {
$line = explode(":", $row);
$results[] = [$line[0], $line[1]];
}
You could also use array_walk with a custom function which does the second level split for you.
This is another approach, not multidimensional:
parse_str(str_replace(array(':','/'), array('=','&'), $workers), $array);
print_r($array);
Shorter in PHP >= 5.4.0:
parse_str(str_replace([':','/'], ['=','&'], $workers), $array);
print_r($array);
yet another approach, since you didn't really give an example of what you mean by "bidimensional" ...
$workers="name1:age1/name2:age2/name3:age3";
parse_str(rtrim(preg_replace('~name(\d+):([^/]+)/?~','name[$1]=$2&',$workers),'&'),$names);
output:
Array
(
[name] => Array
(
[1] => age1
[2] => age2
[3] => age3
)
)