简体   繁体   中英

Deleting Elements In An Array Only When They Are Next To Each Other

I have an array that is composed of information that looks like the following:

['Jay', 'Jay', 'Jay', 'Spiders', 'Dogs', 'Cats', 'John', 'John', 'John', 'Dogs', 'Cows', 'Snakes']

What I'm trying to do is remove duplicate entries but only if they occur right next to each other.

The correct result should look like the following:

['Jay', 'Spiders', 'Dogs', 'Cats', 'John', 'Dogs', 'Cows', 'Snakes']

I'm using PHP but any kind of logic would be able to help me out with this problem.

Here is some code I've tried so far:

$clean_pull = array();
$counter = 0;
$prev_value = NULL;

foreach($pull_list as $value) {
    if ($counter == 0) {
        $prev_value = $value;
        $clean_pull[] = $value;
    }
    else {
        if ($value != $pre_value) {
            $pre_value = value;
        }
    }
    echo $value . '<br>';
}

Francis, when I run the following code:

$lastval = end($pull_list);
for ($i=count($pull_list)-2; $i >= 0; $i--){
    $thisval = $pull_list[$i];
    if ($thisval===$lastval) {
        unset($pull_list[$i]);
    }
    $lastval = $thisval;
}
# optional: reindex the array:
array_splice($pull_list, 0, 0);

var_export($pull_list);

, I get these results:

array ( 0 => 'NJ Lefler', 1 => 'Deadpool', 2 => 'NJ Lefler', 3 => 'Captain Universe: The Hero Who Could Be You', 4 => 'NJ Lefler', 5 => 'The Movement', 6 => 'NJ Lefler', 7 => 'The Dream Merchant', 8 => 'Nolan Lefler', 9 => 'Deadpool', 10 => 'Nolan Lefler', 11 => 'Captain Universe: The Hero Who Could Be You', 12 => 'Nolan Lefler', 13 => 'The Movement', 14 => 'Tom Smith', 15 => 'Deadpool', 16 => 'Tom Smith', 17 => 'Captain Universe: The Hero Who Could Be You', ) 

Your approach (a $prev_value variable) should work fine and you don't need a counter.

Your use of $counter is why your code doesn't work--the first half of the if statement is always executed because $counter is never incremented; and the second half just compares values. The only thing you need to do is compare the current value with the previous value and include the current value only if it differs (or remove it only if it's the same).

It's much easier to see this algorithm if you use functional reduction. Here is an example using array_reduce :

$a = array('Jay', 'Jay', 'Jay', 'Spiders', 'Dogs', 'Cats', 'John', 'John', 'John', 'Dogs', 'Cows', 'Snakes');

$na = array_reduce($a, function($acc, $item){
    if (end($acc)!==$item) {
        $acc[] = $item;
    }
    return $acc;
}, array());

var_export($na);

Note this comparison of var_export($a) (your original array) and var_export($na) (the result produced by the code):

$a = array (            $na = array (    
  0 => 'Jay',             0 => 'Jay',    
  1 => 'Jay',             1 => 'Spiders',
  2 => 'Jay',             2 => 'Dogs',   
  3 => 'Spiders',         3 => 'Cats',   
  4 => 'Dogs',            4 => 'John',   
  5 => 'Cats',            5 => 'Dogs',   
  6 => 'John',            6 => 'Cows',   
  7 => 'John',            7 => 'Snakes', 
  8 => 'John',          )                
  9 => 'Dogs',
  10 => 'Cows',
  11 => 'Snakes',
)

The array_reduce() method does exactly the same thing as the following code:

$na = array();
foreach ($a as $item) {
    if (end($na)!==$item) {
        $na[] = $item;
    }
}

Instead of returning a copy of an array, you can also modify the array in-place using the same algorithm but starting from the end of the array:

$lastval = end($a);
for ($i=count($a)-2; $i >= 0; $i--){
    $thisval = $a[$i];
    if ($thisval===$lastval) {
        unset($a[$i]);
    }
    $lastval = $thisval;
}
# optional: reindex the array:
array_splice($a, 0, 0);

var_export($a);

Keep track of the last element in the array, and skip adding the next element to your new array if you just added it.

Or, you can just check the last element in the array, and see if it's not the current element in your array:

$array = ['Jay', 'Jay', 'Jay', 'Spiders', 'Dogs', 'Cats', 'John', 'John', 'John', 'Dogs', 'Cows', 'Snakes'];
$new = array( array_shift( $array));
foreach( $array as $el) {
    if( !($new[count($new) - 1] === $el)) {
        $new[] = $el;
    }
}

Assuming the array isn't so large that having a second one will cause a problem, the approach you described should work . Does it look like this?

$last = null;
$result = [];

foreach($arr as $item)
    if($item !== $last)
        $result[] = $last = $item;

Re: edit:

  • $pre_value and $prev_value aren't the same thing
  • $counter doesn't change

It looks like you tried to combine a counter approach and a "last" approach somehow.

Define a global variable glob . pass the array: if (array[i] == glob) then remove array[i] else glob = array[i]; keep array[i]; else glob = array[i]; keep array[i];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM