PHP find double values in array and enumerate them - php

Hi I'm looking forward do find an easy solution to find and enumerate double values.
array("Papples", "Gelato", "Gelato", "Banana", "Papples","Papples")
to:
array("Papples", "Gelato", "Gelato2", "Banana", "Papples2","Papples3")
I could do it with a loop with if and write to second array procedure but isn't there a better solution for it?
Thank you!

you can try
<?php
$arr = array("Papples", "Gelato", "Gelato", "Banana", "Papples","Papples");
$countarray = array_count_values($arr);
$resultarray = array();
foreach ($countarray as $key=>$value) {
for ($i = 1; $i <= $value; $i++) {
$resultarray[]=$key.$i;
}
}
print_r($resultarray);
?>

Go with the loop and if, it's not difficult and will be pretty fast.
$delicatessen = [
"Papples", "Gelato", "Gelato", "Banana", "Papples","Papples"
];
foreach ($delicatessen as $e) {
if (#$counter[$e]++) $e .= $counter[$e];
$new[] = $e;
}
Basically what this does is to always add the element to the new array,
clearly, but modifying it or not. The condition is the $counter array
which will store the amount of times an item appears. All is created "on
the fly", PHP allows that.
When we retrieve $counter[$e] this element does not exist yet, so the
returned value makes the condition fail. However there is a side effect
that after the undef is returned, it will be increased (with ++) so
now $counter[$e] will be 1.
If on a future iteration this is accessed again the returned value of
1 will make the condition pass, with the side affect that at the point
the if statement is executed $counter[$e] will already be 2. The
statement concatenated this number to the end of the element.
This way, in the first time nothing is concatenated but there is the
side effect. On next iterations the number is concatenated to the
element.
The # operator is used here to suppress PHP notices. Since you're
dealing with undefined elements on first pass, you would get notices.
Script wouldn't break though. Of course this operator should be used
with caution, but in this case it just really helps simplifying code,
making it less strict.

$arr = array("Papples", "Gelato", "Gelato", "Banana", "Papples","Papples");
$arr_count = array_count_values($arr);
$new_arr = array();
foreach($arr_count as $key=>$val){
if($val > 1){
$k = 1;
for($i=0; $i<$val; $i++){
if($i==0){
$new_arr[] = $key;
}else{
$new_arr[] = $key.++$k;
}
}
}else{
$new_arr[] = $key;
}
}
echo "<pre>"; print_r($new_arr);
Test script: https://3v4l.org/iGf1s

Related

Passing two variables into a 'foreach' loop

I need help regarding a foreach() loop. aCan I pass two variables into one foreach loop?
For example,
foreach($specs as $name, $material as $mat)
{
echo $name;
echo $mat;
}
Here, $specs and $material are nothing but an array in which I am storing some specification and material name and want to print them one by one. I am getting the following error after running:
Parse error: syntax error, unexpected ',', expecting ')' on foreach line.
In the Beginning, was the For Loop:
$n = sizeof($name);
for ($i=0; i < $n; $i++) {
echo $name[$i];
echo $mat[$i];
}
You can not have two arrays in a foreach loop like that, but you can use array_combine to combine an array and later just print it out:
$arraye = array_combine($name, $material);
foreach ($arraye as $k=> $a) {
echo $k. ' '. $a ;
}
Output:
first 112
second 332
But if any of the names don't have material then you must have an empty/null value in it, otherwise there is no way that you can sure which material belongs to which name. So I think you should have an array like:
$name = array('amy','john','morris','rahul');
$material = array('1w','4fr',null,'ff');
Now you can just
if (count($name) == count($material)) {
for ($i=0; $i < $count($name); $i++) {
echo $name[$i];
echo $material[$i];
}
Just FYI: If you want to have multiple arrays in foreach, you can use list:
foreach ($array as list($arr1, $arr2)) {...}
Though first you need to do this: $array = array($specs,$material)
<?php
$abc = array('first','second');
$add = array('112','332');
$array = array($abc,$add);
foreach ($array as list($arr1, $arr2)) {
echo $arr1;
echo $arr2;
}
The output will be:
first
second
112
332
And still I don't think it will serve your exact purpose, because it goes through the first array and then the second array.
You can use the MultipleIterator of SPL. It's a bit verbose for this simple use case, but works well with all edge cases:
$iterator = new MultipleIterator();
$iterator->attachIterator(new ArrayIterator($specs));
$iterator->attachIterator(new ArrayIterator($material));
foreach ($iterator as $current) {
$name = $current[0];
$mat = $current[1];
}
The default settings of the iterator are that it stops as soon as one of the arrays has no more elements and that you can access the current elements with a numeric key, in the order that the iterators have been attached ($current[0] and $current[1]).
Examples for the different settings can be found in the constructor documentation.
This is one of the ways to do this:
foreach ($specs as $k => $name) {
assert(isset($material[$k]));
$mat = $material[$k];
}
If you have ['foo', 'bar'] and [2 => 'mat1', 3 => 'mat2'] then this approach won't work but you can use array_values to discard keys first.
Another apprach would be (which is very close to what you wanted, in fact):
while ((list($name) = each($specs)) && (list($mat) = each($material))) {
}
This will terminate when one of them ends and will work if they are not indexed the same. However, if they are supposed to be indexed the same then perhaps the solution above is better. Hard to say in general.
Do it using a for loop...
Check it below:
<?php
$specs = array('a', 'b', 'c', 'd');
$material = array('x', 'y', 'z');
$count = count($specs) > count($material) ? count($specs) : count($material);
for ($i=0;$i<$count;$i++ )
{
if (isset($specs[$i]))
echo $specs[$i];
if (isset($material[$i]))
echo $material[$i];
}
?>
OUTPUT
axbyczd
Simply use a for loop. And inside that loop, extract values of your array:
For (I=0 to 100) {
Echo array1[i];
Echo array2[i]
}

PHP array get next key/value in foreach() [duplicate]

This question already has answers here:
Get next element in foreach loop
(11 answers)
Closed 9 years ago.
I am looking for a way to get the next and next+1 key/value pair in a foreach(). For example:
$a = array('leg1'=>'LA', 'leg2'=>'NY', 'leg3'=>'NY', 'leg4'=>'FL');
foreach($a AS $k => $v){
if($nextval == $v && $nextnextval == $v){
//staying put for next two legs
}
}
You can't access that way the next and next-next values.
But you can do something similar:
$a = array('leg1'=>'LA', 'leg2'=>'NY', 'leg3'=>'NY', 'leg4'=>'FL');
$keys = array_keys($a);
foreach(array_keys($keys) AS $k ){
$this_value = $a[$keys[$k]];
$nextval = $a[$keys[$k+1]];
$nextnextval = $a[$keys[$k+2]];
if($nextval == $this_value && $nextnextval == $this_value){
//staying put for next two legs
}
}
I've found the solution with complexity O(n) and does not require seeking through array back and forward:
$a = array('leg1'=>'LA', 'leg2'=>'NY', 'leg3'=>'NY', 'leg4'=>'FL');
// initiate the iterator for "next_val":
$nextIterator = new ArrayIterator($a);
$nextIterator->rewind();
$nextIterator->next(); // put the initial pointer to 2nd position
// initiaite another iterator for "next_next_val":
$nextNextIterator = new ArrayIterator($a);
$nextNextIterator->rewind();
$nextNextIterator->next();
$nextNextIterator->next(); // put the initial pointer to 3rd position
foreach($a AS $k => $v){
$next_val = $nextIterator->current();
$next_next_val = $nextNextIterator->current();
echo "Current: $v; next: $next_val; next_next: $next_next_val" . PHP_EOL;
$nextIterator->next();
$nextNextIterator->next();
}
Just remember to test for valid() if you plan to relay on the $next_val and $next_next_val.
Here's one way to do it:
while($current = current($a)) {
$next = next($a);
$nextnext = next($a);
// Comparison logic here
prev($a); // Because we moved the pointer ahead twice, lets back it up once
}
Example: http://3v4l.org/IGCXW
Note that the loop written this way will never examine the last element in your original array. That could be fixed, although with your current logic it doesn't seem to matter since there are no "more" elements to compare the last one to.
Have a look at CachingIterator, as described in this answer:
Peek ahead when iterating an array in PHP
Or use array_keys() is in another answer posted for the same question, e.g.
$keys = array_keys($array);
for ($i = 0; $i < count($keys); $i++) {
$cur = $array[$keys[$i]];
$next = $array[$keys[$i+1]];
}
You can't simply "stay put" in a loop. I suspect you're looking to do something a lot easier than write custom iterators. If you simply want to ignore entries with duplicate keys, then track the last key and compare it to the current one.
$a = array('leg1'=>'LA', 'leg2'=>'NY', 'leg3'=>'NY', 'leg4'=>'FL');
// Prints LA NY FL
$last_v = null;
foreach ( $a as $k => $v ){
if ( $last_v == $v ) {
/**
* Duplicate value, so skip it
*/
continue;
}
echo $v.' ';
$last_v = $v;
}
Funny, I'm programming PHP for a decade (with years pause), but I needed one-by-one walk functions just a week ago.
Here you are: next, prev, reset etc. See "see also" section. Also, check array_keys()

Make a while loop when the array is empty?

I have code that will make an array or arrays of UNKNOWN length because it depends on how many new people have been added to the mysql DB. (this is where I'm getting confused)
The array has $x items, each item is an array of first name, last name, and e-mail address.
I want the loop to run till the array is ended.
$x = 0;
while($array[$x]['per_LastName'] != 'NULL') {
$batch[] = array('EMAIL'=>$array[$x]['per_Email'], 'FNAME'=>$array[$x]['per_FirstName'], 'LNAME'=>$array[$x]['per_LastName']);
$x = $x+1;
}
apparently I'm looping infinity because it uses all the memory.
Use a foreach loop which will loop through all elements of the array.
foreach($array as $key => $value) {
$batch[] = array('EMAIL'=>$value['per_Email'], 'FNAME'=>$value['per_FirstName'], 'LNAME'=>$value['per_LastName']);
}
Instead you should use a for loop
for($x = 0; $x<count($array); $x++){
$batch[] = array('EMAIL'=>$array[$x]['per_Email'], 'FNAME'=>$array[$x]['per_FirstName'], 'LNAME'=>$array[$x]['per_LastName']);
}
why not use foreach and avoid counters and unnecessary checks?
foreach($array as $eachArray)
{
$batch[] = array('EMAIL'=>$eachArray['per_Email'], 'FNAME'=>$eachArray['per_FirstName'], 'LNAME'=>$eachArray['per_LastName']);
}

Foreach key - Possible to seek ahead without " if ( key < wheretoseek ) { continue; } "?

Imagine a simple, but large array with keys 0 to 100000.
When doing a foreach loop of this array, is it possible to 'seek' ahead without doing something like:
foreach($array as $key=>$value){
if($key<10000){
continue;
}
}
We do this kind of operation once in a while thru our codebase. It seams like a bit of a waste of ticks to go thru each of the keys until key is greater then 10000.
Is this possible in php 5.4?
Thanks.
it was possible even in PHP 2.0FI or ALTAIR BASIC
for($i=10000;$i < count($array);$i++){
}
No doubt some nitpickers will come to tell that doing count($array) 90000 times is a waste of ticks too.
However, to get a real performance gain one have to avoid lengthy loops at all.
$rest = array_slice($array, 10000);
Depending on what you want to achieve (here: what you want to do after seeking)
for ($length = count($array), $key = 10000; $key < $length, $key++) {
$value = $array[$key];
}
Assuming the keys are consecutive integers:
$count = count($array);
for ($key = 10000; $key < $count; ++$key) {
$value = $array[$key];
}
I'm not sure if count is O(1) though, so if it's not, you might be better off doing:
$key = 0;
while (isset($array[$key])) {
$value = $array[$key];
++$key;
}
Note that array_key_exists would be required if the key could be considered not set yet exist in the array.
Borrowing from this solution, this would do the trick and set the array pointer at the element you want. This would be the closest you get to seeking the array and not just specifying the interval of keys to loop through.
$start = 10000; // or what ever number you're starting at
while(key($array) < $start) next($array);
You can't use this if you plan to use a foreach-loop (as it resets the pointer), but should be good if you iterate the rest of the array like this
$count = count($array);
do {
$key = key($array);
$value = current($array);
} while($key < $count);

How to get numeric key of new pushed item in PHP?

$arr[] = $new_item;
Is it possible to get the newly pushed item programmatically?
Note that it's not necessary count($arr)-1:
$arr[1]=2;
$arr[] = $new_item;
In the above case,it's 2
end() do the job , to return the value ,
if its help to you ,
you can use key() after to petch the key.
after i wrote the answer , i see function in this link :
http://www.php.net/manual/en/function.end.php
function endKey($array){
end($array);
return key($array);
}
max(array_keys($array)) should do the trick
The safest way of doing it is:
$newKey = array_push($array, $newItem) - 1;
You can try:
max(array_keys($array,$new_item))
array_keys($array,$new_item) will return all the keys associated with value $new_item, as an array.
Of all these keys we are interested in the one that got added last and will have the max value.
You could use a variable to keep track of the number of items in an array:
$i = 0;
$foo = array();
$foo[++$i] = "hello";
$foo[++$i] = "world";
echo "Elements in array: $i" . PHP_EOL;
echo var_dump($foo);
if it's newly created, you should probably keep a reference to the element. :)
You could use array_reverse, like this:
$arr[] = $new_item;
...
$temp = array_reverse($arr);
$new_item = $temp[0];
Or you could do this:
$arr[] = $new_item;
...
$new_item = array_pop($arr);
$arr[] = $new_item;
If you are using the array as a stack, which it seems like you are, you should avoid mixing in associative keys. This includes setting $arr[$n] where $n > count($arr). Stick to using array_* functions for manipulation, and if you must use indexes only do so if 0 < $n < count($arr). That way, indexes should stay ordered and sequential, and then you can rely on $arr[count($arr)-1] to be correct (if it's not, you have a logic error).

Categories