LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 07-21-2006, 03:12 PM   #1
joelhop
Member
 
Registered: Mar 2004
Location: Pennsylvania::USA
Distribution: Fedora Core 6
Posts: 100

Rep: Reputation: 15
Question PHP Coding Question


I am using the php usort()command to sort an array.

Example Array:

$sdArray = array( array( 'Fred', 'Chode', 31 ),
array( 'Shaggy', 'Hippie', 23 ),
array( 'Scooby', 'Dog', 7));


Example ascORDER() function:

function ascORDER($x, $y)
{
if ( $x[0] == $y[0] )
return 0;
else if ( $x[0] < $y[0] )
return -1;
else
return 1;
}

Example usort:

usort($sdArray, 'ascORDER');

This works all fine and good, resorts the array by key position 0, or the name (Fred, Shaggy, Scooby). However if I want to change what I want to sort by, I have to go into ascORDER() and change the 0 to 1 or a 2 to change which key I want to sort by. This also works, but what I would like to do is rewrite the ascORDER() function to replace the hard coded key position to a variable as such:

function ascORDER($x, $y)
{
if ( $x[$z] == $y[$z] )
return 0;
else if ( $x[$z] < $y[$z] )
return -1;
else
return 1;
}

Where $z is the key position. Then I would simply like to pass with value of $z with:

usort($sdArray, 'ascORDER'); + ($z)

Obviously that isn't the solution, but does anyone have any idea how you can pass a variable to the user-defined comparison function (in this case ascORDER) when using usort?


Thanks!
-Karl
 
Old 07-21-2006, 04:50 PM   #2
demon_vox
Member
 
Registered: May 2006
Location: Argentina
Distribution: SuSE 10
Posts: 173

Rep: Reputation: 30
Hi,
well you cant do that with usort because its interface is not thought to do that.
What you can do:

* Write a wrapper for usort, and then you can have two strategies: a function por each field you want to sort; or setting a global variable so you can get the key value inside your ascORDER function).
The first one would be something like:

Code:
function myUSort(&$myArray,$key) {
  $mySortingFunction = array(
    0 => ascORDER,
    1 => otherORDER
  );
  usort(myArray, $mySortingFunction[$key]);
}
or, a more scary solution with global variables (WARNING THIS HAS SIDE-EFFECT!!!!!!!!!!!!!!!!!!!!!!!!!!):

Code:
function myUSort(&$myArray,$key) {
  $GLOBALS["__SORT_BY"] = $key);
  usort(myArray, ascORDER);
}

function ascORDER($x, $y) {
  $z = $GLOBALS["__SORT_BY"];
  if ( $x[$z] == $y[$z] )
    return 0;
  else if ( $x[$z] < $y[$z] )
    return -1;
  else
    return 1;
}
I do not like the second solution because it uses global variables which sucks.


The other solution is to implement yourself the sorting algorithm which wont be that hard anyway and you can add the interface you like.


Hope this is useful!
Cheers
 
Old 07-21-2006, 11:01 PM   #3
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
There are a couple of solutions to your dilemma, that I can think of.
  1. Have multiple sort functions - one for each dimension
  2. Put it in a class and have a static variable point to the dimension you're interested in.

The first approach is the standard way to address these kind of problems, and with a little work you can get it to mirror the approach that you wanted to use, as indicated by demon_vox. The second avoid the use of global by wrapping it in a class but unless it is already in a class it is probably not worth the extra effort.
 
Old 07-23-2006, 10:22 AM   #4
joelhop
Member
 
Registered: Mar 2004
Location: Pennsylvania::USA
Distribution: Fedora Core 6
Posts: 100

Original Poster
Rep: Reputation: 15
Thank you for your solutions!


demonvox, I don't think the wrapper option would work for me since in addition to needing a $z variable field sort by, I also need this solution to be applicable to any number of fields in an array, the function needs to be able to work with an array with 3 fields or 10 fields etc. So hard coding a sortby function for each field sort by would be impossible. I did further pursue the global idea you suggested and came up with this:

<?php

$z=2;

function ascORDER($x,$y)
{
global $z;
if ( $x[$z] == $y[$z] )
return 0;
else if ( $x[$z] < $y[$z] )
return -1;
else
return 1;
}

$sdArray = array( array( 'Fred', 'Chode', 31 ),
array( 'Daphne', 'Hottie', 23 ),
array( 'Scooby', 'Dog', 7));

usort($sdArray, 'ascORDER');

var_dump($sdArray);

?>

This works and I can change $z to whatever I want and apply this to an array of any size. I am fairly new to globals, but I am interested in your warning about globals, what side effects would I be looking at here?

You also mentioned writing my own sorting algorthm, I thought about this as well, usort would be perfect if it simply supported passing a variable to the user-defined comparison function called within usort. I was wondering where I could find the code for usort, or how to even begin writing my own, any ideas, examples etc?
 
Old 07-23-2006, 10:26 AM   #5
joelhop
Member
 
Registered: Mar 2004
Location: Pennsylvania::USA
Distribution: Fedora Core 6
Posts: 100

Original Poster
Rep: Reputation: 15
graemef thank you for your reply,

I don't think the multiple sort function option will for for me since I need to have the function be flexible enough to support arrays of any field size, so I wouldn't know from operation to operation how many sort functions I would need.
As you can see in the above post I did solve the problem using a global variable $z.

But there seems to be some kind of a negative stimga to using globals? Can your further elaborate on this, and let me know if you see any possible negative side-effects in my solution?

Also you had mentioned using classes to solve this problem? Can you further elaborate on how i might do this, and if that is a better solution than the globals?

Thank you!
 
Old 07-23-2006, 12:42 PM   #6
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
The main problem with globals is if another piece of code also has a global with the same name, they will in fact be the same variable. So you have written some code using a global variable $z, then I could write some code which also used a global variable called $z, yours holds an array dimension mine holds the name of the favourite zoo animal.

If there is an overlap then the result is that my code stops your code from working, a side effect of my code changing your variable (and my variable). Because of the difficulty of working out why your code no longer works global variables are strongly discouraged.

Using a class provides you with a namespace, that it the $z will belong to your class. If I produce a $z in my class, because the classes will have separate names the $z will be different variables and there is no side effect.
 
Old 07-23-2006, 01:03 PM   #7
joelhop
Member
 
Registered: Mar 2004
Location: Pennsylvania::USA
Distribution: Fedora Core 6
Posts: 100

Original Poster
Rep: Reputation: 15
graemef,

I can definitely see what you are saying. As the project size increased with numerous developers just managing who's using what global would be a project in and of itself.

I have a very limited knowledge of class usage. How greatly will replacing the global $z with a class definied $z affect my existing code? Also, do you know of any good tutorials or examples I could use to switch my code from global usage to class usage?

Thank You so much!
 
Old 07-23-2006, 05:57 PM   #8
demon_vox
Member
 
Registered: May 2006
Location: Argentina
Distribution: SuSE 10
Posts: 173

Rep: Reputation: 30
hi,
well graemef told you about the side effects so I cant elaborate much more on that. I can only add a little detail of how you would use it.
If you are using global variables every time you want to sort an array with that method you would write:

Code:
$GLOBALS["z"] = 4;
usort($sdArray, 'ascORDER');
so, for sorting you will need two lines of code, being the first one extremely little declarative. If I have to read it I will trully wonder what the first line will do. Plus, you must never forget that line or you'll get unpredicting results. And catching this error es hard, but make this error is easy because you can just accidentaly erase the line by accident.

The Class solution that mentioned graemef is a good idea in theory but I dont see how to pass a method call as the usort second parameter (I tried it now but it doesnt seem to be working). If there is a way, then it's a good idea, but I just cant make it work :P


As regard of writing your own sorting function I meant to write it in PHP. If you want to hack the C code of PHP it is ok, but:
  1. You need to know C
  2. You will have to recompile PHP
  3. You will only be able to use where this modify nonstandar PHP is installed
What I had in mind is writting it in PHP itself.

I hope this is useful.
Cheers!
 
Old 07-23-2006, 06:16 PM   #9
joelhop
Member
 
Registered: Mar 2004
Location: Pennsylvania::USA
Distribution: Fedora Core 6
Posts: 100

Original Poster
Rep: Reputation: 15
Yeah, the global solution works, I'm having my $z sort variable being passed via the browser and grabbing it up into the variable with a GET, but globals do seem like risky business. I have began investigating the class option, but I have much more reading until I have a good enough understand of classes to do something useful with them.

Am I possibly approaching this problem from the wrong angle? Is there a more standard way to sort an array variably by any of it's keys?
 
Old 07-23-2006, 08:55 PM   #10
joelhop
Member
 
Registered: Mar 2004
Location: Pennsylvania::USA
Distribution: Fedora Core 6
Posts: 100

Original Poster
Rep: Reputation: 15
I'm having some trouble passing an my array into a class. I can pass variables into the class without a problem but not the array. Any ideas?
 
Old 07-23-2006, 10:16 PM   #11
demon_vox
Member
 
Registered: May 2006
Location: Argentina
Distribution: SuSE 10
Posts: 173

Rep: Reputation: 30
Hi,
what do you mean with "passing an array into a class"? What you do is pass the array as an method's argument of a class.
For instance:

Code:
class MyCoolClass {
  function sort(&$anArray) {
    // Here you do the magic with the array which is in the variable $anArray
    print_r($anArray); //just for the sake of completeness
  }

}


$myData = array("hola", "hello", "hi");
$mySorter = new MyCoolClass();

$mySorter->sort($myData);
That should work. Is this what you are trying to do?

Cheers!
 
Old 07-24-2006, 05:37 PM   #12
joelhop
Member
 
Registered: Mar 2004
Location: Pennsylvania::USA
Distribution: Fedora Core 6
Posts: 100

Original Poster
Rep: Reputation: 15
I ended up solving the problem this way:

function sortSTUFF($a)
{
function ascORDER($x,$y)
{
$z = (isset ($_GET['sortby'])) ? $_GET['sortby'] : 0;
if ( $x[$z] == $y[$z] )
return 0;
else if ( $x[$z] < $y[$z] )
return -1;
else
return 1;
}

usort($a, 'ascORDER');
return $a;
}

I know it's a bit hackish at this time, but $a is an array being passed in, and I got around the problem of passing a variable to the user-defined sort function used by usort, by simply defining $z with a get inside the user-defined sort function itself. I was also able to replace 'ascORDER' with a variable that would allow me to call any function. I am going to continue working on this looking more in the direction of a class solution, as it would be much cleaner. Thank you very much for all your help, I could never have gained as clear of an understanding of the picture without it.
 
Old 07-24-2006, 05:52 PM   #13
demon_vox
Member
 
Registered: May 2006
Location: Argentina
Distribution: SuSE 10
Posts: 173

Rep: Reputation: 30
Good thing you have it worked.
But just for the record, when you use the _GET array, you are still using a "global" variable. But in this case you are taking an array key ('sortby' in this case). Should you use a web page that has a link with this field in, and you try to sort an array, they will still colapse each other.
Since this is an "internal" variable, maybe it is better to have a name lika "__MyUsortVariable" or something like that, so you never step on it.

This is just a though, maybe it is useful, maybe not

Cheers!
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
PHP Coding Question joelhop Programming 2 07-20-2006 06:16 PM
PHP 4.4.0 Coding Error Phaux Linux - Software 1 12-30-2005 07:05 PM
Coding java in a php script mrobertson Programming 44 06-27-2005 01:16 PM
coding a php server mrobertson Linux - General 22 06-05-2005 01:06 PM
php coding with knoppix mrobertson Linux - General 1 06-01-2005 01:30 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:47 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration