Problems with SORT_FLAG_CASE flag - php

I am tring to do (like) a 2 dimensional array, case insensitive.
I have:
foreach ($rows as $key=>$row) {
$names[$key]=$row['Name'];
}
array_multisort($rows,SORT_STRING|SORT_FLAG_CASE,$names);
The above ends up producing the same result (with or without case flag).
Sick of staring at this, any ideas from somebody outside?

First of all SORT_FLAG_CASE is only available in PHP v5.4+ so I suggest checking which version of PHP you are running (maybe 'uksort' could help if 5.3ish).
If not, make sure all the values that you put into $names lowercase or uppercase.
You have the order of the arguements $rows and $names reversed in the call to array_multisort.
Lastly if it comes from a database (or some other manner that means you cant change the data on the way into the array) then you can use array_walk.
Hope that helps

Since I ran into this with PHP 5.3.16, I thought I'd share my simple solution: just convert your keys to lower (or upper) case, e.g.:
foreach ($rows as $key=>$row) {
$names[$key]=strtolower($row['Name']);
}
array_multisort($names,SORT_STRING,$rows);
I also swapped the $rows & $names and removed the SORT_FLAG_CASE (to get rid of the log message).

You can also do a sort within a sort, so you can use usort with strcasecmp:
foreach ($rows as $key=>$row) {
$names[$key]=row['Name'];
}
array_multisort(usort($names,strcasecmp),$rows);

Above answer didn't work, because the first array got mingled while the other one didn't. So I wrote a general multidimensional array case insensitive compare function. It also can use multiple keys:
function array_casecmp($keys) {
if (gettype($keys) != "array") $keys = func_get_args();
return function ($a, $b) use ($keys) {
foreach($keys as $value) {
$akeys = $akeys . $a[$value];
$bkeys = $bkeys . $b[$value];
}
return strcasecmp($akeys, $bkeys);
};
}
Use it like:
usort($files,strcasecmp(array(0,1)); // with standard array
usort($files,strcasecmp(1); // single key
usort($files,strcasecmp(0,1); // arguments are converted to array
usort($files,strcasecmp("dir","link")); // you can also use symbolic keys
usort($files,strcasecmp(0,1,2,3,4,...); // use as many keys as you like
Keep in mind that the keys are concatenated, so maybe you have to use str_pad in your array colums to keep them seperated in the right way.

Related

Calling an array element inside another array

I think this is a naive question, but I can't find the proper syntax.
I have this code:
for ($i=1; $i<count($MyArray1); $i++){
$element=$MyArray1[$i];
$foo = $AnotherArray[$element];
echo $foo;
}
How can I skip the second line? I mean, the third line to be something like
$foo = $AnotherArray[$MyArray1[$i]];
for ($i=1; $i<count($MyArray1); $i++){
echo $AnotherArray[$MyArray1[$i]];
}
You can skip a fair amount of that code to make it a bit clearer. Firstly use foreach instead of for as it's a much more reliable way of iterating over arrays. Secondly I've broken down what you're trying to do, to simplify how you're getting it. Basically using the values of one array as the keys of another. So how to do it in three lines:
foreach(array_intersect_key($AnotherArray, array_flip($MyArray1)) as $value) {
echo $value;
}
This is using the excellent array_intersect_key method to grab all of the values from $AnotherArray with keys that match in the other array. As you want to use the values, we use array_flip to swap the keys and values, then just loop over the result and echo it.

sorting 2d array with individual comparator using phps array_multisort

I got a 2d-array containing a "column" on which this whole array is to be sorted. As I learned here, it is quite straightforward using array_multisort. My problem is, that this to be sorted over column contains values that needs to be compared in an unusual way. So I thought of something like this:
function main(){
$toBeSorted = array(array(...), ..., array(...));
$sortColumnIndex = n;
$sort_column = array();
//Code copied from provided link
foreach ($toBeSorted as $row)
$sort_column []= $row[$sortColumnIndex];
array_multisort($this->comparator(),$sort_column, $toBeSorted);
}
function comparator(a,b){
return 1;
}
As you can see, I want to pass my comparator to that sort-function. I probably think to much in a non-php way.
There is the usort function, which sorts by using a callback.
Otherwise you could have a look at the array_walk and array_walk_recursive functions, which iterate over an array and apply a function to every member.
I solved it by transforming my sorting space in one, that array_multisort can handle:
...
$sortColumn = array();
foreach($toBeSorted as $value){
$sortColumn[] = $this->transform($value);
}
array_multisort($sortColumn, $toBeSorted);
...
my transformation function simply does everything I imagined the callback would do.
function transform($value){
//i.e. return real part of complex number
//or parse strings or any kind of strange datatypes
}

Does php have c++'s std::pair?

I'd like to make an associative array in PHP where the key is a pair of strings.
At first I was considering concatenating the strings with some sort of unique divider in the middle, and then separating them later, but this seems like a hacky workaround for using a pair.
Consider the following code:
$andrew = array('Andrew', 'Rasmussen');
$john = array('John', 'Smith');
$container[$andrew] = 15;
$container[$john] = 12;
$pair = array('Andrew', 'Rasmussen');
if (array_key_exists($pair, $container)) {
echo 'true';
} else {
echo 'false';
}
Obviously this code will not work because you can't use an array as a key in an array in PHP. Is there a good way to do something like this without concatenating and then later parsing the strings?
Edit
I have a reason for wanting to do this. I have an array(key=string1,value=array(key=string2,value=occurrences)) and I'm trying to find the top 5 (in terms of occurrences) of string pairs. So I'm basically trying to flatten this into a 1d array and then sort it so I can easily grab the top 5. But to do this I'll need to be able to extract the strings out separately after I've sorted, which can be done with the divider algorithm explained above, but this is not preferable, which is why I'm asking for an alternative.
How about serializeing the key?
$pair = array('Andrew', 'Rasmussen');
if (array_key_exists( serialize( $pair), $container)) {
echo 'true';
} else {
echo 'false';
}
You can make use of multidimensional arrays (by using it as $container["Andrew"]["Rasmussen"] for example).
Also, you can encapsulate all the "hacking" (be it two-dimensional arrays or string concatenation) in your custom ArrayIndexedByPairs class, which could be like the following:
interface IArrayIndexedByPairs {
public Add($key1, $key2, $value);
public Contains($key1, $key2);
public Get($key1, $key2);
}

Extracting Data from JSON Using PHP

Here's a test jason feed
{"MEMBERS":[{"NAME":"Joe Bob","PET":["DOG"]}, {"NAME":"Jack Wu","PET":["CAT","DOG","FISH"]}, {"NAME":"Nancy Frank","PET":["FISH"]}]}
What I'm attempting to do is extract data if PET contains CAT or FISH or both. Another user suggested a filter as such:
$filter = array('CAT', 'FISH');
// curl gets the json data (this part works fine but is not shown for brevity)
$JSONarray=json_decode($JSONdata,true);
foreach($JSONarray['MEMBERS'] as $p) {
if (in_array($p['PET'], $filter)) {
echo $p['NAME'] . '</br>';
}
}
But it's not returning anything.
Note: edited based on comments below
Use strings to access the array and not uninitialized constants.
$p['PET'] is an array. You have to use some other method to compare it against $filter, e.g. array_intersect:
foreach($JSONarray['MEMBERS'] as $p) {
$diff = array_intersect($filter, $p['PET']);
if (!empty($diff)) {
echo $p['NAME'].'</br>';
}
}
DEMO
It should work like this:
foreach($JSONarray['MEMBERS'] as $p) {
if (array_diff($p['PET'], $filter) != $p['PET']) {
echo $p['NAME'].'</br>';
}
}
Remember to always use quotes when you are trying to access an element of an associative array. Without quotes, PHP tries to interpret it as a constant (throwing a Notice on failure). So instead of $a[index] do $a['index']. Please also see Why is $foo[bar] wrong?
In your code, $p['PET'] will be an array of pet names, not one pet name. Testing with in_array() won't be successful, because it will try to find the whole array in $filter. In my code example, I used array_diff() which will find the difference between the two arrays, then I compare it to the original array. If they match, the $filter pets were not found.
First, you need to use quotes on your array keys:
$JSONarray['MEMBERS']
$p['PET']
$p['NAME']
Secondly, you can't use in_array as it assumes 'needle' to be the array('CAT', 'FISH') and not any one of it's values.
(The parameter order was also the other way around)
Here's a method using array_intersect:
foreach($JSONarray['MEMBERS'] as $p) {
$test = array_intersect($filter, $p['PET']);
if (count($test)>0) {
print( $p['NAME'].'</br>' );
}
}

PHP key value pairs vs. arrays

I'm trying to pass key values pairs within PHP:
// "initialize"
private $variables;
// append
$this->variables[] = array ( $key = $value)
// parse
foreach ( $variables as $key => $value ) {
//..
}
But it seems that new arrays are added instead of appending the key/value, nor does the iteration work as expect. Please let me know what the proper way is.
Solution
$this->variables[$key] = $value;
did the trick - the iteration worked as described above.
I think you may be looking for:
$this->variables[$key] = $value;
The way you have it right now you are creating an array of arrays, so you would have to do this:
foreach($this->variables as $tuple) {
list($key, $value) = $tuple;
}
Referring to Perl, but helps understand the difference between hashes and arrays:
Some people think that hashes are like arrays (the old name 'associative array' also indicates this, and in some other languages, such as PHP, there is no difference between arrays and hashes.), but there are two major differences between arrays and hashes. Arrays are ordered, and you access an element of an array using its numerical index. Hashes are un-ordered and you access a value using a key which is a string.
Source: http://perlmaven.com/perl-hashes

Categories