2

I have a array that looks like this:

Array
(
    [100] => Array
        (
            [user_id] => 100
            [nest] => Array
                (
                )

        )

    [200] => Array
        (
            [user_id] => 200
            [nest] => Array
                (
                    [300] => Array
                        (
                            [user_id] => 300
                            [nest] => Array
                                (
                                )

                        )

                    [400] => Array
                        (
                            [user_id] => 400
                            [nest] => Array
                                (
                                )

                        )

                    [500] => Array
                        (
                            [user_id] => 500
                            [nest] => Array
                                (
                                )

                        )

                )

        )

    [600] => Array
        (
            [user_id] => 600
            [nest] => Array
                (
                )

        )

    [700] => Array
        (
            [user_id] => 700
            [nest] => Array
                (
                )

        )

    [800] => Array
        (
            [user_id] => 800
            [nest] => Array
                (
                )

        )

    [900] => Array
        (
            [user_id] => 900
            [nest] => Array
                (
                )

        )

)

I want to be able to show only 5 element at a time. How can I make a function that takes a range (1-5 or 5-10, etc.) and shows that range of elements from the array.

For example, the range 1-5 would show only elements 100, 200, 300, 400, and 500 from the array. Range 5-10 would show elements 500, 600, 700, 800, and 900.

Thank you!

  • http://php.net/manual/en/function.array-slice.php – quickshiftin Dec 17 '14 at 21:27
  • @quickshiftin That seems to only work for top-level elements if I'm not mistaken? Doing `array_slice($array, 0, 2)` shows elements `100` and `200` and *every element within them*, instead of just showing elements `100` and `200` alone. –  Dec 17 '14 at 21:31
  • If you only want to show the top level elements you'll need to strip out their children by hand one way or another. But since your elements are arrays themselves there's not really much value at the top level. Maybe as simple as nuking the 'nest' elements from the second level after an `array_slice` is what you're after? – quickshiftin Dec 17 '14 at 21:38
  • No, I don't only want to show top level elements. *"For example, the range 1-5 would show only elements `100, 200, 300, 400, and 500` from the array. Range 5-10 would show elements `500, 600, 700, 800, and 900`."* –  Dec 17 '14 at 21:41
  • `array_slice` returns nested elements, did you even try it? Sorry I misread your reply to my first comment. – quickshiftin Dec 17 '14 at 21:46
  • Okay, I'll try to explain this better. Let's say I want a range of 1-3. That means that only elements `100, 200, and 300` should show. However, `array_slice($comments, 0, 3)` is returning elements `100, 200, and *600*`. In other words, `array_slice` only works on the top-most level elements instead of actually going inside nested arrays. –  Dec 17 '14 at 21:49
  • 2 questions. Is your array at most 2 levels deep? and will there only ever be one key with 200, 300 etc? The function is a simple nesting of 2 foreach loops in that case. – quickshiftin Dec 17 '14 at 21:52
  • The array can be infinitely deep. Key names are unique. –  Dec 17 '14 at 21:54
  • I just hooked you up with a custom slice function in my answer, let me if that's what you were after. – quickshiftin Dec 17 '14 at 22:09
  • Take a look at my new answer, I have a feeling it's closer to what you're looking for. – quickshiftin Dec 18 '14 at 05:05

3 Answers3

1

If I'm interpreting it correctly, it looks like you'd need to flatten the array first, and then array_slice will work the way you want it to.

Specifically, something like this:

function flatten(array $array) {
  $return = array();
  array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
  return $return;
}

Taken from this question.

Community
  • 1
  • 1
Chris Barcroft
  • 562
  • 5
  • 12
1

Here you are my friend

function customSlice(array $a, $iStartRange, $iEndRange) {
    $aRange = range($iStartRange, $iEndRange);
    $oIt    = new RecursiveIteratorIterator(
                  new RecursiveArrayIterator($a),
                  RecursiveIteratorIterator::SELF_FIRST);

    $aResult = array();
    foreach($oIt as $name => $element)
        if(in_array($name, $aRange))
            $aResult[$name] = $element;

    return $aResult;
}

Example

$aExample = array(
    100 => array('user_id' => 100, 'nest' => array()),
    200 => array('user_id' => 200, 'nest' => array(
        300 => array('user_id' => 300, 'nest' => array()),
        400 => array('user_id' => 400, 'nest' => array()),
        500 => array('user_id' => 500, 'nest' => array())
    )),
    600 => array('user_id' => 600, 'nest' => array()),
    700 => array('user_id' => 700, 'nest' => array()),
    800 => array('user_id' => 800, 'nest' => array()),
    900 => array('user_id' => 900, 'nest' => array())
);

$aSliced = customSlice($aExample, 100, 500);
quickshiftin
  • 66,362
  • 10
  • 68
  • 89
  • Can you explain what the `100 * $iRange` part does? –  Dec 17 '14 at 22:10
  • Your keys are 100, 200 etc instead of 1, 2 etc. It's just a simple mapping. The core code is here for you though, you should be able to tweak it for your needs. – quickshiftin Dec 17 '14 at 22:10
  • I should have mentioned that the keys can be completely different each time (they're user_ids taken from the database). :/ –  Dec 17 '14 at 22:14
  • Then you can just use `$aRange = range($iStartRange, $iEndRange)` instead of the first `foreach`; I'll revise the answer. – quickshiftin Dec 17 '14 at 22:15
  • Are you sure this works? I've tried `customSlice($array, 0, 5)` but it only returns 1 result. Can you show me how you got it working on http://writecodeonline.com/php/ ? –  Dec 17 '14 at 22:35
  • I used your example array; pasting a full example under my answer. – quickshiftin Dec 17 '14 at 22:37
  • Yeah, per your exmaple, you don't have anything between 0 and 5.... So you need to put 0-500 for your example array. Assuming there can be id's like 1, 2, 3 ... 100, 500 etc... – quickshiftin Dec 17 '14 at 22:39
  • That's what my original solution was accounting for w/ the `* 100` bit, but then you said no they can be any integer over 0 so I revised it. – quickshiftin Dec 17 '14 at 22:40
  • Oh I see what you mean. Is there a way to instead say "I want the first 25 elements" (i.e. a range of `0-25`)? Or, "I need the elements from 25 - 50" (i.e. the elements from the 25th element to the 50th element)? –  Dec 17 '14 at 22:41
  • For that I would do something like flatten the array first, either with `RecursiveIteratorIterator` or an `array_walk_recurssive` call like the other answer, then `array_slice` the result. – quickshiftin Dec 17 '14 at 22:44
0

Somewhat different from my first answer, but likely more towards what OP is after. This function flattens the array, and slices from the flattened perspective. It does the slicing inline, rather than after the flattening. Also, I've commented out but included code to strip out the 'nest' elements in the result, otherwise there could be lots of redundant data in them. And finally, I've put some decent comments on this one. Enjoy!

/**
 * Slice any array based on flattened perspective.
 * @param array $a Array to slice
 * @param int $iStartRange Starting index to slice (inclusive)
 * @param int $iEndRange Ending index to slice (inclusive)
 * Return array Sliced subset of input array.
 */
function recursive_array_slice(array $a, $iStartRange, $iEndRange)
{
    // Flatten out the inbound array
    $oIt = new RecursiveIteratorIterator(
               new RecursiveArrayIterator($a),
               RecursiveIteratorIterator::SELF_FIRST);

    $aResult = array(); // The sliced result
    $i       = 1;       // Track which element we're on
    foreach($oIt as $name => $element) {
        // Not a very rigorous check, but this filters
        // candidates down to ones we're likely looking for
        if(!is_int($name))
            continue;

        // If the current element is in the range of
        // interest, include it in the results
        if($i >= $iStartRange && $i <= $iEndRange) {
            $aResult[$name] = $element;
            // Optional if you don't want a ton of redundant
            // data in the results
            // unset($aResult[$name]['nest']);
        }   

        // Increment the count of the current element
        $i++;

        // Bail if we've gone past the range of interest
        if($i > $iEndRange)
            break;
    }

    return $aResult;
}
quickshiftin
  • 66,362
  • 10
  • 68
  • 89