How can I do the following without lots of complicated code?
Explode each value of an array in PHP (I sort of know how to do this step)
Discard the first part
Keep the original key for the second part (I know there will be only two parts)
By this, I mean the following:
$array[1]=blue,green
$array[2]=yellow,red
becomes
$array[1]=green //it exploded [1] into blue and green and discarded blue
$array[2]=red // it exploded [2] into yellow and red and discarded yellow
I just realized, could I do this with a for...each loop? If so, just reply yes. I can code it once I know where to start.
given this:
$array[1] = "blue,green";
$array[2] = "yellow,red";
Here's how to do it:
foreach ($array as $key => $value) {
$temp = explode(",", $value, 2); // makes sure there's only 2 parts
$array[$key] = $temp[1];
}
Another way you could do it would be like this:
foreach ($array as $key => $value) {
$array[$key] = preg_replace("/^.+?,$/", "", $value);
}
... or use a combination of substr() and strpos()
Try this:
$arr = explode(',','a,b,c');
unset($arr[0]);
Although, really, what you're asking doesn't make sense. If you know there are two parts, you probably want something closer to this:
list(,$what_i_want) = explode('|','A|B',2);
foreach ($array as $k => &$v) {
$v = (array) explode(',', $v);
$v = (!empty($v[1])) ? $v[1] : $v[0];
}
The array you start with:
$array[1] = "blue,green";
$array[2] = "yellow,red";
One way of coding it:
function reduction($values)
{
// Assumes the last part is what you want (regardless of how many you have.)
return array_pop(explode(",", $values));
}
$prime = array_map('reduction', $array);
Note: This creates a different array than $array.
Therefore $array == $prime but is not $array === $prime
Related
I am trying to group some foreach results based on the first 3 sets of characters.
For example i am currently listing sku codes for products and they look like this:
REF-MUSBOM-0500-ORA
REF-PROCOF-0001-LAT
REF-WHEREF-0001-TRO
REF-WHEREF-0001-ORA
REF-SHAKER-0700-C/B
REF-CREMON-0100-N/A
REF-GLUSUL-0090-N/A
REF-CRECAP-0090-N/A
REF-ALBFER-0120-N/A
REF-TSHCOT-LARG-BLK
REF-TSHCOT-MEDI-BLK
REF-ALBMAG-0090-N/A
REF-GYMJUG-2200-N/A
REF-OMEGA3-0090-N/A
REF-NEXGEN-0060-N/A
REF-VITAD3-0100-N/A
REF-SSSHAK-0739-N/A
REF-GINKGO-0090-N/A
REF-DIGEZY-0090-N/A
REF-VEST00-MEDI-N/A
REF-VEST00-LARG-N/A
REF-CREMON-0250-N/A
REF-MSM----0250-N/A
REF-GRNTEA-0100-N/A
REF-COLOST-0100-N/A
REF-GLUCHO-0090-N/A
REF-ZINCMA-0100-N/A
REF-BETALA-0250-N/A
REF-DRIBOS-0250-N/A
REF-HMB000-0090-N/A
REF-ALACID-0090-N/A
REF-CLA000-0090-N/A
REF-ACETYL-0090-N/A
REF-NXGPRO-0090-N/A
REF-LGLUTA-0250-N/A
REF-BCAA20-0200-N/A
REF-FLAPJA-0012-ACR
REF-FLAPJA-0012-MAP
REF-LCARNI-0100-N/A
REF-CORDYC-0090-N/A
REF-CREMON-0500-N/A
REF-BCAAEN-0330-APP
REF-PREWKT-0300-FPU
REF-TESFUS-0090-N/A
REF-AMIIFUS-0300-GAP
REF-AMIIFUS-0300-WME
REF-BCAINT-0400-FPU
REF-KRILLO-0090-N/A
REF-AMIIFUS-0300-PLE
REF-AMIIFUS-0300-FPU
REF-BCAINT-0400-WME
REF-ENZQ10-0090-N/A
REF-THERMO-0100-N/A
REF-LGLUTA-0500-N/A
REF-RBAR00-0012-DCB
REF-RBAR00-0012-PBC
REF-RBAR00-0012-WCR
REF-IMHEAV-2200-CHO
REF-PROCOF-0012-N/A
REF-DIEPRO-0900-STR
REF-DIEPRO-0900-BOF
REF-DIEPRO-0900-CHO
REF-INWPRO-0900-VAN
REF-INWPRO-0900-BOF
REF-INWPRO-0900-BCS
REF-INWPRO-0900-CHO
REF-INWPRO-0900-CMI
REF-INWPRO-0900-RAS
REF-INWPRO-0900-STR
REF-INWPRO-0900-CIN
REF-INWPRO-0900-CPB
REF-EGGPRO-0900-CHO
REF-EGGPRO-0900-VAN
REF-MICCAS-0909-CHO
REF-MICCAS-0909-CMI
REF-MICCAS-0909-VAN
REF-MICCAS-0909-STR
REF-BCAA50-0500-N/A
REF-MICWHE-0909-STR
REF-MICWHE-0909-VAN
REF-MICWHE-0909-CHIO
REF-MICWHE-0909-BAN
REF-1STOXT-2030-STR
REF-1STOXT-2030-VAN
REF-1STOXT-2030-CHO
REF-MUSBOM-0600-BCH
REF-MUSBOM-0600-FPU
REF-MUSBCF-0600-BCH
REF-MUSBCF-0600-FPU
REF-VEGANP-2100-STR
REF-VEGANP-2100-CHO
REF-INMPRO-2270-CPB
REF-DIETMR-2400-CPB
REF-INMPRO-2270-SCR
REF-INMPRO-2270-VIC
REF-MATRIX-1800-FRU
REF-INMPRO-2270-BOF
REF-MATRIX-1800-CHO
REF-INMPRO-2270-CHO
REF-ONESTO-2100-CHO
In the above list there are 2 skus which are:
REF-WHEREF-0001-TRO
REF-WHEREF-0001-ORA
The first 3 sets of characters split by - are the same. What would be the best approach of grouping all results leaving me an array something like this:
Array
(
[REF-WHEREF-0001] => Array
(
[0] => REF-WHEREF-0001-TRO
[1] => REF-WHEREF-0001-ORA
)
)
Are the first 3 groups (excluding the multiple -) always 13 characters? Then do something like this:
<?php
$arr = ["REF-MUSBOM-0500-ORA",
"REF-PROCOF-0001-LAT",
"REF-WHEREF-0001-TRO",
"REF-WHEREF-0001-PPL"];
$resultArr = [];
foreach ($arr as $sku) {
$resultArr[substr($sku, 0, 15)][] = $sku;
}
var_dump($resultArr);
If that length varies you might want to work with a regex or the strpos() of the third -.
I must say that I think you could come up with this yourself, since you were already thinking in the right direction i.e. foreach()
EDIT: Because I found other solutions more elegant looking, I decided to compare efficiency. This solution is a lot faster than the other ones.
I always create a new array with the index that I need for group, try this:
$arr=array('REF-MUSBOM-0500-ORA',
'REF-PROCOF-0001-LAT',
'REF-WHEREF-0001-TRO');
$newarr=array();
foreach($arr as $a){
$b=explode('-',$a);
array_pop($b);
$b=implode("-", $b);
$newarr[$b][]=$a;
}
echo '<pre>',print_r($newarr),'</pre>';
You will need to pick a group with some basics use of explode, implode and str_replace.
What does this solution do.
loop through the array of your items
explode to get last item index of exploded string assuming that it
would be dynamic in the end
implode & str_replace again to find out string of group name
And last strpos & in_array to have sample reponse
Solution
$array = array(
'REF-MUSBOM-0500-ORA',
'REF-PROCOF-0001-LAT',
'REF-WHEREF-0001-TRO',
'REF-WHEREF-0001-ORA',
'REF-SHAKER-0700-C/B',
'REF-CREMON-0100-N/A',
'REF-GLUSUL-0090-N/A',
'REF-CRECAP-0090-N/A',
'REF-ALBFER-0120-N/A',
);
$new_array = array();
foreach ($array as $key => $val) {
$group_arr = explode('-', $val);
$end = end($group_arr);
$combined_group = implode('-', $group_arr);
$group = str_replace('-' . $end, '', $combined_group);
if (strpos($val, $group) !== false && !in_array($group, $new_array)) {
$new_array[$group][] = $val;
}
}
echo '<pre>';print_r($new_array);echo '</pre>';
See demo on Sandbox
Is there any way that I can remove the successive duplicates from the array below while only keeping the first one?
The array is shown below:
$a=array("1"=>"go","2"=>"stop","3"=>"stop","4"=>"stop","5"=>"stop","6"=>"go","7"=>"go","8"=>"stop");
What I want is to have an array that contains:
$a=array("1"=>"go","2"=>"stop","3"=>"go","7"=>"stop");
Successive duplicates? I don't know about native functions, but this one works. Well almost. Think I understood it wrong. In my function the 7 => "go" is a duplicate of 6 => "go", and 8 => "stop" is the new value...?
function filterSuccessiveDuplicates($array)
{
$result = array();
$lastValue = null;
foreach ($array as $key => $value) {
// Only add non-duplicate successive values
if ($value !== $lastValue) {
$result[$key] = $value;
}
$lastValue = $value;
}
return $result;
}
You can just do something like:
if(current($a) !== $new_val)
$a[] = $new_val;
Assuming you're not manipulating that array in between you can use current() it's more efficient than counting it each time to check the value at count($a)-1
I have a string that will be exploded to get an array, and as we know, the output array key will start from 0 as the key to the first element, 1 for the 2nd and so on.
Now how to force that array to start from 1 and not 0?
It's very simple for a typed array as we can write it like this:
array('1'=>'value', 'another value', 'and another one');
BUT for an array that is created on the fly using explode, how to do it?
Thanks.
$exploded = explode('.', 'a.string.to.explode');
$exploded = array_combine(range(1, count($exploded)), $exploded);
var_dump($exploded);
Done!
Just use a separator to create a dummy element in the head of the array and get rid of it afterwards. It should be the most efficient way to do the job:
function explode_from_1($separator, $string) {
$x = explode($separator, $separator.$string);
unset($x[0]);
return $x;
}
a more generic approach:
function explode_from_x($separator, $string, $offset=1) {
$x = explode($separator, str_repeat($separator, $offset).$string);
return array_slice($x,$offset,null,true);
}
$somearray = explode(",",$somestring);
foreach($somearray as $key=>$value)
{
$otherarray[$key+1] = $value;
}
well its dirty but isn't that what php is for...
Nate almost had it, but needed a temporary variable:
$someArray = explode(",",$myString);
$tempArray = array();
foreach($someArray as $key=>$value) {
$tempArray[$key+1] = $value;
}
$someArray = $tempArray;
codepad example
$array = array('a', 'b', 'c', 'd');
$flip = array_flip($array);
foreach($flip as &$element) {
$element++;
}
$normal = array_flip($flip);
print_r($normal);
Try this, a rather funky solution :P
EDIT: Use this instead.
$array = array('a', 'b', 'b', 'd');
$new_array = array();
$keys = array_keys($array);
for($i=0; $i<count($array); $i++) {
$new_array[$i+1] = $array[$i];
}
print_r($new_array);
I agree with #ghoti that this task is probably an XY Problem. I can't imagine a valid/professional reason to start keys from 1 -- I've never needed this functionality in over 10 years of development. I'll offer a compact looping approach, but I'll probably never need it myself.
After instatiating a counter which is one less than the desired first key, you can use a body-less foreach() as a one-liner.
Code: (Demo)
$i = 0;
$result = [];
foreach (explode('.', 'a.string.to.explode') as $result[++$i]);
var_export($result);
I have an array_flipped array that looks something like:
{ "a" => 0, "b" => 1, "c" => 2 }
Is there a standard function that I can use so it looks like (where all the values are set to 0?):
{ "a" => 0, "b" => 0, "c" => 0 }
I tried using a foreach loop, but if I remember correctly from other programming languages, you shouldn't be able to change the value of an array via a foreach loop.
foreach( $poll_options as $k => $v )
$v = 0; // doesn't seem to work...
tl; dr: how can I set all the values of an array to 0? Is there a standard function to do this?
$array = array_fill_keys(array_keys($array), 0);
or
array_walk($array, create_function('&$a', '$a = 0;'));
You can use a foreach to reset the values;
foreach($poll_options as $k => $v) {
$poll_options[$k] = 0;
}
array_fill_keys function is easiest one for me to clear the array. Just use like
array_fill_keys(array_keys($array), "")
or
array_fill_keys(array_keys($array), whatever you want to do)
foreach may cause to decrease your performance to be sure that which one is your actual need.
Run your loop like this, it will work:
foreach( $poll_options as $k => $v )
$poll_options[$k] = 0;
Moreover, ideally you should not be able to change the structure of the array while using foreach, but changing the values does no harm.
As of PHP 5.3 you can use lambda functions, so here's a functional solution:
$array = array_map(function($v){ return 0; }, $array);
You have to use an ampersand...
foreach( $poll_options as &$v)
$v = 0;
Or just use a for loop.
you can try this
foreach( $poll_options as $k => &$v )
$v = 0;
Address of $v
array_combine(array_keys($array), array_fill(0, count($array), 0))
Would be the least manual way of doing it.
There are two types for variable assignment in PHP,
Copy
Reference
In reference assignment, ( $a = &$b ), $a and $b both, refers to the same content. ( read manual )
So, if you want to change the array in thesame time as you doing foreach on it, there are two ways :
1- Making a copy of array :
foreach($array as $key=>$value){
$array[$key] = 0 ; // reassign the array's value
}
2 - By reference:
foreach($array as $key => &$value){
$value = 0 ;
}
I would like to take an array, say:
array("one", "two", "three");
and make it into an array of arrays, like:
$someArray["one"]["two"]["three"];
The array of arrays ($someArray) would have to be created by some sort of loop as the initial array is created by an explode() so i don't know how deep $someArray would be.
I hope this is clear, thanks all for your time!
I am reading up on it at the moment myself, would array_map() work for this?
You can do this:
$path = array("one", "two", "three");
$ref = &$arr;
foreach ($path as $key) {
if (!isset($ref[$key])) break;
$ref = &$ref[$key];
}
At the end $ref is a reference to $arr['one']['two']['three'] if it exists. And if you replace break by $ref[$key] = array() you will build an array with that structure instead.
You should use array_reduce.
The solution is quite simple.
To do the trick, reverse the array and only then apply the reduction.
$a = array('a','b','c');
$x = array_reduce(array_reverse($a), function ($r, $c) {
return array($c=>$r);
},array());
EDIT an expanded and explained version:
In php we don't have a function to go deep into an array automatically but we haven't to.
If you start from the bottom, we will be able to enclose an array into the previous one
with a simple assignation.
$a = array('a','b','c');
$result=array(); // initially the accumulator is empty
$result = array_reduce(
array_reverse($a),
function ($partialResult, $currentElement) {
/* enclose the partially computed result into a key of a new array */
$partialResult = array($currentElement=>$partialResult);
return $partialResult;
},
$result
);
By the way I prefer the shorter form. I think it is a functional idiom and doesn't need further explanation to a middle experienced developer (with a bit of functional background). The second one add a lot of noise that, it is suitable to learn but source
of distraction into production code (obviously I'm referring to function with just a return statement).
i'm not sure why you would want this.
But but the basis of what your wanting would be like this
$numbers = array("one", "two", "three");
$array = array();
$pointer = &$array;
$last_val = NULL;
foreach($numbers as $key => $val){
if(!empty($pointer[$last_val])){
$pointer = &$pointer[$last_val];
$pointer = new array($val);
$last_val = $val;
}else{
$pointer = new array($val);
$last_val = $val;
}
}
This should then right what you want to $array;
This is untested but i think that should work if it does not just tell me what its doing and i will have a look
$arrNew = array();
$ref = &$arrNew;
$arrParts = array("one", "two", "three");
foreach($arrParts as $arrPart){
$ref[$arrPart] = array();
$ref = &$ref[$arrPart];
}
When you print $arrNew, It will print this..
Array
(
[one] => Array
(
[two] => Array
(
[three] => Array
(
)
)
)
)