Consecutive occurrence array reduction

I'm in the middle of learning PHP, and the following list-related issue has occurred. Language doesn't really matter, so I'll give it to you in pseudo-code. Of course, the answers to the pseudo codes are beautiful.

Let's say there is a list of two different repeating elements - for example, two separate characters. So my list looks something like this:

myList = [C, C, D, C, D, D, D, C, C, D, C, D, C, C, ...]

However, this is not the form I want. Instead, the list should look like this:

myList* = [CC, D, C, DDD, CC, D, C, D, CC, ...]
myList* = shorten(myList)

What is the most elegant way to turn a one-character list into one that contains continuous lines of subsequent characters as its elements? My solution seems pretty crap to me, given that it includes multiple nested if statements, various state variables, and other nasty things.

Pseudo code away! Thanks a lot in advance for any implementation

shorten()

you are leaving me.

+3
source share
5 answers

Using PHP 5.3 Closure and array_reduce:

ini_set('error_reporting', E_ALL);

function shorten(array $list) {
    return array_reduce($list, function($a, $b) {
        $lastIdx = count($a) - 1;
        if(isset($a[$lastIdx]) && strstr($a[$lastIdx], $b)) $a[$lastIdx] .= $b;
        else $a[] = $b;

        return $a;
    }, array());
}


$list = array('C', 'C', 'D', 'C', 'D', 'D', 'D', 'C', 'C', 'D', 'C', 'D', 'C', 'C');
$expected = array('CC', 'D', 'C', 'DDD', 'CC', 'D', 'C', 'D', 'CC');

$listShortened = shorten($list);
assert($expected === $listShortened);
+2
source

You can do this with a single scan of the array, tracking the current character and the last character:

function shorten($myList) {
        $myList[] = '';                         // add a dummy char at the end of list.
        $result = array();                      // result to be returned.
        $last_char = $myList[0];                // initilize last char read.
        $combine = $last_char;                  // initilize combined string.
        for($i=1;$i<count($myList);$i++) {      // go from index 1 till end of array.
                $cur_char = $myList[$i];        // current char.
                if($cur_char != $last_char) {   
                        $result[] = $combine;   // time to push a new string into result.
                        $combine = $cur_char;   // reset combine string.
                } else {
                        $combine.=$cur_char;    // is cur char is same as prev..append it.
                }
                $last_char = $cur_char;         // for next iteration cur become last.
        }
        return $result;                         // return result.
}

Code in action

0
source
$myList = array('C', 'C', 'D', 'C', 'D', 'D', 'D', 'C', 'C', 'D', 'C', 'D', 'C', 'C');

function shorten($list) {
    $newList = array();

    foreach($list as $key => $entry) {
        if ($key == 0) {
            $newList[] = $entry;
        } elseif ($entry == substr($newList[count($newList)-1],0,1)) {
            $newList[count($newList)-1] .= $entry;
        } else {
            $newList[] = $entry;
        }
    }

    return $newList;
}

$shortenedList = shorten($myList);

var_dump($myList);
echo '<br />';
var_dump($shortenedList);
0
source
$result = array();
$word = '';
$lastChar = $myList[0];
foreach($myList as $char){
    if($lastChar !== $char){
        $result[] = $word;
        $word = '';
    }
    $word .= $char
}
0
source

A bit shorter alternative to Max answer ...

$mylist = array("a","b","b","b","c","c","d");
function shorten($array) {
  $str = implode("",$array); // step 1: make string from array of chars
  preg_match_all("/(\w)\\1*/",$str,$matches); // step 2: split into chunks
  return $matches[0]; // step 3: that all
}
print_r(shorten($mylist));
0
source

Source: https://habr.com/ru/post/1771958/


All Articles