0

let's say I have an object, $obj, that after this foreach() loop:

foreach($obj as $row){
    echo 'file_id:'.$row->file_id.'-name:'.$row->name.'<br>';
}

would look like this:

file_id:321-name:321-is-good
file_id:322-name:322-is-better
file_id:323-name:323-is-best

How can I sort $obj such that I can choose what is the first echo'd $row? For example, if I plugged in 322 somewhere, the result would look like this:

file_id:322-name:322-is-better
file_id:323-name:323-is-best
file_id:321-name:321-is-good

and if I plugged in 323:

file_id:323-name:323-is-best
file_id:321-name:321-is-good
file_id:322-name:322-is-better

I know it probably involves usort() but I can't wrap my head around what needs to be done.

thoughts?

thanks, tim

1 Answer 1

2

Assuming you want to sort on file_id at a specific start, appending what comes before, which is also sorted on file_id:

$sort = '323';
usort($arr,function($a,$b) use ($sort) {
   //normal sorting for low-ids after high-ids
   if($a->file_id < $sort && $a->file_id < $sort){
      return strcmp($a->file_id,$b->file_id);
   } 
   //if only $a is smaller $a should be later
   if($a->file_id < $sort) return 1;
   //if only $b is smaller $a should be earlier
   if($b->file_id < $sort) return -1;
   //both above $sort, sort normally
   return strcmp($a->file_id,$b->file_id);
 });

Working example with an Object instead of a Array:

<?php
//build a test with arrays is easier;
$arr = new ArrayObject(array(
    array('file_id' => '321','name' => '321 is good'),
    array('file_id' => '322','name' => '322 is better'),
    array('file_id' => '323','name' => '323 is best')));
//cast all to object for purposes of testing objects
foreach($arr as &$val) $val = (object)$val;
//when you used a reference _always_ unset... trust me on this one
unset($val);

$sort = '323';
// we define the callback separately because for this test we use it more then once
// don't pay much attention to the reference as &$sort, this is just to alter it in 
// multiple tests, and should not be needed in the actual implementation.

$callback = function($a,$b) use (&$sort) {
   //normal sorting for low-ids after high-ids
   if($a->file_id < $sort && $b->file_id < $sort){ //$a & $b indeed, not $a twice ;)
      return strcmp($a->file_id,$b->file_id);
   }
   //if only $a is smaller $a should be later
   if($a->file_id < $sort) return 1;
   //if only $b is smaller $a should be earlier
   if($b->file_id < $sort) return -1;
   //both above $sort, sort normally
   return strcmp($a->file_id,$b->file_id);
};

//322 first:
$sort='322';
$arr->uasort($callback);
var_dump($arr);

//323 first:
$sort='323';
$arr->uasort($callback);
var_dump($arr);

//321 again first:
$sort='321';
$arr->uasort($callback);
var_dump($arr);

//non-existing:
$sort='400';
$arr->uasort($callback);
var_dump($arr);



object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(3) {
    [1]=>
    object(stdClass)#5 (2) {
      ["file_id"]=>
      string(3) "322"
      ["name"]=>
      string(13) "322 is better"
    }
    [2]=>
    object(stdClass)#6 (2) {
      ["file_id"]=>
      string(3) "323"
      ["name"]=>
      string(11) "323 is best"
    }
    [0]=>
    object(stdClass)#4 (2) {
      ["file_id"]=>
      string(3) "321"
      ["name"]=>
      string(11) "321 is good"
    }
  }
}
object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(3) {
    [2]=>
    object(stdClass)#6 (2) {
      ["file_id"]=>
      string(3) "323"
      ["name"]=>
      string(11) "323 is best"
    }
    [0]=>
    object(stdClass)#4 (2) {
      ["file_id"]=>
      string(3) "321"
      ["name"]=>
      string(11) "321 is good"
    }
    [1]=>
    object(stdClass)#5 (2) {
      ["file_id"]=>
      string(3) "322"
      ["name"]=>
      string(13) "322 is better"
    }
  }
}
object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(3) {
    [0]=>
    object(stdClass)#4 (2) {
      ["file_id"]=>
      string(3) "321"
      ["name"]=>
      string(11) "321 is good"
    }
    [1]=>
    object(stdClass)#5 (2) {
      ["file_id"]=>
      string(3) "322"
      ["name"]=>
      string(13) "322 is better"
    }
    [2]=>
    object(stdClass)#6 (2) {
      ["file_id"]=>
      string(3) "323"
      ["name"]=>
      string(11) "323 is best"
    }
  }
}
object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(3) {
    [0]=>
    object(stdClass)#4 (2) {
      ["file_id"]=>
      string(3) "321"
      ["name"]=>
      string(11) "321 is good"
    }
    [1]=>
    object(stdClass)#5 (2) {
      ["file_id"]=>
      string(3) "322"
      ["name"]=>
      string(13) "322 is better"
    }
    [2]=>
    object(stdClass)#6 (2) {
      ["file_id"]=>
      string(3) "323"
      ["name"]=>
      string(11) "323 is best"
    }
  }
}

Sign up to request clarification or add additional context in comments.

6 Comments

-@Wrikken, yes $sort will be defined on the fly, thank you let me try your code...
I have not tested it, so I am not responsible for any parse or other errors, but it should help get the idea across ;)
-@Wrikken, so do I need to typecast $obj as an $array first? Also, i'm having trouble returning the re-ordered $obj. Do I just do this: $obj=usort($obj, function($a...?
-@wrikken, i'm confused, this is is not keeping the names together with the file_ids. Also, 321 is always coming first, would you mind clarifying your answer to address these 2 problems? thanks,
Aha, I only now see your 'list' of rows was an object itself, missed that the first time around. Yes, for sorting to work you either need an array (or, define a custom next() & others for the Iterator interface), or extend something like an ArrayObject (which was what I did for this example).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.