Compare 2 arrays and preserve the row number Background:

You have an eCommerce order of 10 products but you want to refund only 5 of them. The stock managing system needs to preserve the order of row number (orderline) when you do the returns, but don't send the items that are not refunded.

The order looks like this:

"Poduct1" Orderline ="1"
"Poduct2" Orderline ="2"
"Poduct3" Orderline ="3"
"Poduct4" Orderline ="4"


Refund all except Product2 and Product3 becomes:

"Poduct1" Orderline ="1"
"Poduct4" Orderline ="4"


But the creditmemo object returns it like this:

"Poduct1" Orderline ="1"
"Poduct4" Orderline ="2"


Because there is nothing in the refunded object about non-refunded items, my strategy is to compare the refund object with the order one and spot the difference (empty place).

Get order items and build and array of all SKUs:

$items = $products-&gt;getAllVisibleItems();
$all_skus = array();

    foreach ($items as $key =&gt; $item) {

        $all_sku = $item-&gt;getData("sku");
        $all_skus[] = $all_sku;

    }


Get refunded items and build an array of all SKUs:

    $all_memo_skus = array();
    foreach ($creditmemo-&gt;getAllItems() as $key =&gt; $item) {

        $memo_sku = $item-&gt;getData('sku');          
        $all_memo_skus[] = $memo_sku;

    }


Check the difference between them:

$memo_diff = array_diff($all_skus, $all_memo_skus);


returns keys and SKUs. But I'm interested only in the key, the position where there is an empty place:

$memo_diff = array_keys($memo_diff);


because the array starts at 0, but the Orderline rows have to begin with 1, add 1 to each item of the array:

        $memo_increase = array();
        foreach($memo_diff as $val){
            $memo_increase[] = $val + 1;
        }


If there are consecutive numbers group them, for example if rows 2,3,4,5 are not refunded, you want the Orderline to jump to 6.

Here I am grouping the consecutive rows:

$result  = array(); 
        $temp = array(); 
        foreach($memo_increase as $val) { 
            if(next($memo_increase) == ($val + 1)){
                $temp[] = $val; 
            }
            else{ 
                if(count($temp) &gt; 0) { 
                    $temp[] = $val; 
                    $result[]  = $temp[0].'-'.end($temp); 
                    $temp   = array(); 
                } 
                else{ 
                    $result[] = $val; 
                }
            }
        }


This will return something like array("1", "4-9", "12") if rows 1,4,5,6,7,8,9,12 are missing.

//start array key from 1 instead of 0


array_unshift($result,"");
        unset($result[0]);


Then loop through each refunded item and assign it the right Orderline:

    $i = 1;

    foreach ($creditmemo-&gt;getAllItems() as $key =&gt; $item) {

            //if item is inside a grouped element, i.e 2-7 put the orderline at 2 then the next one at 8 
            foreach($result as $val){
                if(strpos($val,"-")){
                    $piece = explode("-", $val);
                    if(($piece[0]) == $i){
                        $orderline = $piece[0];
                        $i = $piece[1] + 1; 

                    }
                }
            }
//if item is single
            if(in_array($i, $result)){ 
                $orderline = $i+1; 
                $i++;
            }               
            else{ 
                $orderline = $i; 
            }


It is overly complex for such a simple task. Is there a better way?
The stock managing system needs to preserve the order of row number (orderline) when you do the returns, but don't send the items that are not refunded.


If that's the requirement, then you should store the row number in the database at the time that the order is placed.  The problems that you are having come from trying to rebuild this information later.  If you want something to be persistent, store it.  You would only want to build it on the fly if you want it to change with other changes.  But in this case, that's explicitly not what you want.  

This would be easier to answer if you included more code.  For example, how do you write to your database?  I'm suggesting a change in that.  How do you read from your database?  I'm suggesting that you read another column.  How do you build your data structures?  They might change as well.  

In the following:


    foreach ($creditmemo-&gt;getAllItems() as $key =&gt; $item) {

            //if item is inside a grouped element, i.e 2-7 put the orderline at 2 then the next one at 8 
            foreach($result as $val){
                if(strpos($val,"-")){
                    $piece = explode("-", $val);
                    if(($piece[0]) == $i){
                        $orderline = $piece[0];
                        $i = $piece[1] + 1; 

                    }
                }
            }
//if item is single
            if(in_array($i, $result)){ 
                $orderline = $i+1; 
                $i++;
            }               
            else{ 
                $orderline = $i; 
            }



You could just say 

    foreach ($creditmemo-&gt;getAllItems as $item) {
        $orderline = $item-&gt;getOrderLine();


Of course, this adds additional work when inserting into the database, but since you don't provide that, we can't help you make changes to it.  Nor can we help with the changes to the $item object, as we don't see how it's built.