Re-arrange PHP array and return the 3 lowest

Viewed 56

I have a list of an array something like this

[0] => Array
    (
        [id] => 104
        [book_id] => 32
        [price] => 55
    )

[1] => Array
    (
        [id] => 117
        [book_id] => 76
        [price] => 65
    )

[2] => Array
    (
        [id] => 135
        [book_id] => 77
        [price] => 65
    )

[3] => Array
    (
        [id] => 100
        [book_id] => 78
        [price] => 65
    )

[4] => Array
    (
        [id] => 110
        [book_id] => 21
        [price] => 85
    )

[5] => Array
    (
        [id] => 107
        [book_id] => 35
        [price] => 90
    )

[6] => Array
    (
        [id] => 108
        [book_id] => 64
        [price] => 90
    )

[7] => Array
    (
        [id] => 130
        [book_id] => 101
        [price] => 100
    )

If you see the array, it arranged by price from lowest to largest. I'm trying to re-arrange the array to get only 3 lowest prices and filter out the rest. Means that, when I do the filtration, my array must contain the prices from 55-85 which is from index 0-4.

Is there a way I can filter it like that? Thank you.

3 Answers

I think this could be rather simple with a basic foreach loop.

If you see the array, it arranged by price from lowest to largest.

So, I am assuming your prices are already sorted and additional sort is redundant.

You could just loop over and maintain a count of how many different prices are encountered. Once $cnt reaches 4, you can stop collecting the data and print the result.

<?php

$cnt = 0;
$result = [];

foreach($arr as $index => $data){
    if($index === 0 || $data['price'] > $arr[$index-1]['price']){
        $cnt++;
    }

    if($cnt === 4) break;
    $result[] = $data;
}    

echo "<pre>";
print_r($result);

Here's a fairly manual approach that extracts the prices from the data and uses it in a filter...

$items = array(
  array( 'id' => 104, 'book_id' => 32, 'price' => 55 ),
  array( 'id' => 117, 'book_id' => 76, 'price' => 65 ),
  array( 'id' => 135, 'book_id' => 77, 'price' => 65 ),
  array( 'id' => 100, 'book_id' => 78, 'price' => 65 ),
  array( 'id' => 101, 'book_id' => 21, 'price' => 85 ),
  array( 'id' => 107, 'book_id' => 35, 'price' => 90 ),
  array( 'id' => 108, 'book_id' => 64, 'price' => 90 ),
  array( 'id' => 130, 'book_id' => 101, 'price' => 100 ),
);

// extract unique prices out of the data
$prices = array_unique( array_column( $items, 'price' ) );

// sort the prices (ascending)
sort( $prices );

// extract three prices
$threePrices = array_slice( $prices, 0, 3 );

// filter the items that have a price in the lowest three prices array
$lowestItems = array_filter( $items, function( $item ) use ( $threePrices ) {

  return in_array( $item['price'], $threePrices );

});

print_r( $lowestItems );

//  Array
//  (
//      [0] => Array
//          (
//              [id] => 104
//              [book_id] => 32
//              [price] => 55
//          )
//  
//      [1] => Array
//          (
//              [id] => 117
//              [book_id] => 76
//              [price] => 65
//          )
//  
//      [2] => Array
//          (
//              [id] => 135
//              [book_id] => 77
//              [price] => 65
//          )
//  
//      [3] => Array
//          (
//              [id] => 100
//              [book_id] => 78
//              [price] => 65
//          )
//  
//      [4] => Array
//          (
//              [id] => 101
//              [book_id] => 21
//              [price] => 85
//          )
//  
//  )

A good method is to rearrange the array to become an associative multidimensional array on price.
That way you can easily slice out three items and you have the keys in the main array as the prices in easy access.

$items = array(
  array( 'id' => 104, 'book_id' => 32, 'price' => 55 ),
  array( 'id' => 117, 'book_id' => 76, 'price' => 65 ),
  array( 'id' => 135, 'book_id' => 77, 'price' => 65 ),
  array( 'id' => 100, 'book_id' => 78, 'price' => 65 ),
  array( 'id' => 101, 'book_id' => 21, 'price' => 85 ),
  array( 'id' => 107, 'book_id' => 35, 'price' => 90 ),
  array( 'id' => 108, 'book_id' => 64, 'price' => 90 ),
  array( 'id' => 130, 'book_id' => 101, 'price' => 100 ),
);


foreach($items as $sub){
    // Build new array
    $new[$sub["price"]][] = $sub;
}
//ksort($new); // if you need to sort on price, should not be needed.

$lowest3 = array_slice($new, 0, 3 , true); // slice three and preserve keys with true

var_dump($lowest3);

Returns:

array(3) {
  [55]=>
  array(1) {
    [0]=>
    array(3) {
      ["id"]=>
      int(104)
      ["book_id"]=>
      int(32)
      ["price"]=>
      int(55)
    }
  }
  [65]=>
  array(3) {
    [0]=>
    array(3) {
      ["id"]=>
      int(117)
      ["book_id"]=>
      int(76)
      ["price"]=>
      int(65)
    }
    [1]=>
    array(3) {
      ["id"]=>
      int(135)
      ["book_id"]=>
      int(77)
      ["price"]=>
      int(65)
    }
    [2]=>
    array(3) {
      ["id"]=>
      int(100)
      ["book_id"]=>
      int(78)
      ["price"]=>
      int(65)
    }
  }
  [85]=>
  array(1) {
    [0]=>
    array(3) {
      ["id"]=>
      int(101)
      ["book_id"]=>
      int(21)
      ["price"]=>
      int(85)
    }
  }
}

https://3v4l.org/2hARj

Related