Trying to sort my array to show the group with meat categoryName to be first element in array. Is there a better way to sort this array than running two for loops?
My array looks like this
Array
(
[0] => Array
(
[categoryId] => C4ye95zr403cx9wqi11eo
[categoryName] => set
[categoryStatus] => true
)
[1] => Array
(
[categoryId] => Cj-v2b7szu3jpph1rvu03
[categoryName] => meat
[categoryStatus] => true
)
I want to rearrange the array by categoryName == meat to be first element in array.
Currently i'm just running two loops to do this.
$temp = array();
foreach($array as $k => $v)
{
if($v['categoryName']=="meat")
{
$temp[] = $menu[$k];
$setEmpty = false;
unset($array[$k]);
}
}
foreach($menu as $k=>$v)
{
$temp[] = $array[$k];
}
You can utilize usort:
usort($array, function ($element) {
return $element['categoryName'] === 'meat' ? 0 : 1;
});
The documentation states the following about the callback:
The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
So, in order to push the meat category to the beginning, all you need to do is say that everything else is greater than it.
You can check the fiddle for a test.
How to sort multidimensional array. This is what my array looks like
[0] => Array
(
[id] => 1
[title] => 3A
[active] => 1
)
[1] => Array
(
[id] => 1
[title] => A
[active] => 1
)
[2] => Array
(
[id] => 1
[title] => 2A
[active] => 1
)
[3] => Array
(
[id] => 1
[title] => B
[active] => 1
)
I have tried several usort methods, but cannot seem to get this to work. I am needing the array sorted so that it will sort by numeric then by alpha numeric like so: A,B,2A,3A.
I am not sure if this would be possible without adding a position field to dictate what order the titles are suppose to be in, or am I missing something here?
You can build a "key" for each item where the digit part is padded on the left with 0s, this way, the sort function can perform a simple string comparison:
$temp = [];
foreach ($arr as $v) {
$key = sscanf($v['title'], '%d%s');
if (empty($key[0])) $key = [ 0, $v['title'] ];
$key = vsprintf("%06d%s", $key);
$temp[$key] = $v;
}
ksort($temp);
$result = array_values($temp);
demo
This technique is called a "Schwartzian Transform".
As #Kargfen said, you can use usort with your custom function. Like this one :
usort($array, function(array $itemA, array $itemB) {
return myCustomCmp($itemA['title'], $itemB['title']);
});
function myCustomCmp($titleA, $titleB) {
$firstLetterA = substr($titleA, 0, 1);
$firstLetterB = substr($titleB, 0, 1);
//Compare letter with letter or number with number -> use classic sort
if((is_numeric($firstLetterA) && is_numeric($firstLetterB)) ||
(!is_numeric($firstLetterA) && !is_numeric($firstLetterB)) ||
($firstLetterA === $firstLetterB)
) {
return strcmp($firstLetterA, $firstLetterB);
}
//Letters first, numbers after
if(! is_numeric($firstLetterA)) {
return -1;
}
return 1;
}
This compare-function is just based on the first letter of your titles, but it can do the job ;-)
You can resolve that problem with help of usort and custom callback:
function customSort($a, $b)
{
if ($a['id'] == $b['id']) {
//if there is no number at the beginning of the title, I add '1' to temporary variable
$aTitle = is_numeric($a['title'][0]) ? $a['title'] : ('1' . $a['title']);
$bTitle = is_numeric($b['title'][0]) ? $b['title'] : ('1' . $b['title']);
if ($aTitle != $bTitle) {
return ($aTitle < $bTitle) ? -1 : 1;
}
return 0;
}
return ($a['id'] < $b['id']) ? -1 : 1;
}
usort($array, "customSort");
At first the function compares 'id' values and then if both items are equal it checks 'title' values.
I'm probably [super]overthinking this. I'm trying to analyze an array with values like [1,9], [4,6] [5,5], [6,4], [9,1] and duplicate digits (I'm having a super brain fart and can't even remember the term for numbers like this) remove (the last two) so that only [1,9], [4,6] [5,5] are printed.
I was thinking that turning this array into a string and using preg_match, but I'm pretty sure this wouldn't work even if I had the correct regex.
If you have an array of pairs like this:
$x = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1)
);
Here is one way to get the unique pairs:
foreach ($x as $pair) {
sort($pair);
$unique_pairs[implode(',', $pair)] = $pair;
}
This uses string representations of each sorted pair as keys in a new array, so the result will have distinct values by definition.
As far as the printing them out part of your question, once you have the unique values you can loop over them and print them out in whichever format you like, for example:
foreach ($unique_pairs as $pair) { vprintf("[%d,%d]<br>", $pair); }
It looks like elements are distributed symmetrically.
We can cut the array in two halves and get only the first half with array_slice():
$array = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 4
[1] => 6
)
[2] => Array(
[0] => 5
[1] => 5
)
)
Demo at Codepad.
ceil() is used to round the number up to the next highest integer if there is an even number of items in the array. Example: if there is 3 items in the array, 5 / 2 will return 2.5, we want 3 items so we use ceil(2.5) which gives 3.
Example with 3 items:
$array = array(
array(1,9),
array(5,5),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 5
[1] => 5
)
)
Example with 4 items:
$array = array(
array(1,9),
array(7,7),
array(7,7),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 7
[1] => 7
)
)
If I'm correct in understanding what you are trying to do, you want to remove the final 2 elements from the array?
There is a function in PHP called array_pop that removes the final element from the array.
$array = array_pop($array);
So if you run this twice, you will remove the final 2 elements from the array.
This is how I'd do it (and I hope I am not overthinking this :))
$stringArray = array();
$stringArray[] = '1,9';
$stringArray[] = '4,6';
$stringArray[] = '5,5';
$stringArray[] = '6,4';
$stringArray[] = '9,1';
foreach($stringArray as &$numString) {
$numString = explode(',', $numString);
usort($numString, function($a, $b) {return $a - $b;});
$numString = implode(',', $numString);
}
$a = array_unique($a);
print_r($a);
You basically explode every element into a subarray, sort it and then implode it back. After calling the array_unique, you're left with unique values in the array.
The output would be
Array
(
[0] => 1,9
[1] => 4,6
[2] => 5,5
)
The result you suggest treats [a,b] as equivalent to [b,a] which makes the problem a lot more complex. The code below gives the result you asked for, but without really understanding what the problem is that you are trying to fix and whether [1,9] is equivalent to [9,1] in the solution:
$a=array(array(1,9),array(4,6),...
$dup=array();
for ($i=0; $i<count($a) -1; $i++) {
for ($j=$i+1; $j<count($a); $j++) {
if (($a[$i][0]==$a[$j[0] && $a[$i][1]==$a[$j[1])
|| ($a[$i][0]==$a[$j[1] && $a[$i][1]==$a[$j[0])) {
$dup[]=$j;
}
}
}
foreach ($dup as $i) {
unset($a[$i]);
}
So I'm actually going to assume your question to have a different meaning than everyone else did. I believe what you're asking is:
How do you filter out array items where a reverse of the item has already been used?
<?php
// The example set you gave
$numberSets = [[1, 9], [4, 6], [5, 5], [6, 4], [9, 1]];
// Initialize an empty array to keep track of what we've seen
$keys = [];
// We use array filter to get rid of items we don't want
// (Notice that we use & on $keys, so that we can update the variable in the global scope)
$numberSets = array_filter($numberSets, function($set) use(&$keys) {
// Reverse the array
$set = array_reverse($set);
// Create a string of the items
$key = implode('', $set);
// Get the reverse of the numbers
$reversedKey = strrev($key);
// If the palindrome of our string was used, return false to filter
if (isset($keys[$reversedKey])) {
return false;
}
// Set the key so it's not used again
// Since $keys is being passed by reference it is updated in global scope
$keys[$key] = true;
// Return true to NOT filter this item, since it or it's reverse were not matched
return true;
});
var_dump($numberSets);
Let's say we have arrays like below.
$arr00 = [0,1,2,...,9]; // It includes 9 arrays. So the score should be 9.
$arr01 = [0,1,...,8]; // score = 8
...
$arr09 = [0]; // score = 0
ArrScore (definition): If an array include an array with all elements it
gets one point. So in this case $arr00's total score is 9. Because it
includes all other 9 arrays. And $arr09's score will be 0.
Actual Conditions
Our array elements could be random numbers. (not sequent orders ascending +1)
There could be thousands of arrays.
Our arrays are always flat. (no duplicated element in an array)
We are using php (any theoretical approach is also ok)
Think that you have a standard PC and you will order these arrays everyday once. (No need for the result of "which arr eats which ones". Just ArrScores.)
Goal is to order arrays by ArrScore. And we need ArrScores. What should be the approach? (Theoretical or practical)
If I understood right, this might help:
function compare($a,$b) {
if(count(array_intersect($a, $b)) == count($a)) return -1;
else return 1;
}
$arr0 = [0,2,4,7];
$arr1 = [7,0,2,9,4];
$arr2 = [4,2];
$arr = [$arr0,$arr1,$arr2];
usort($arr,"compare");
foreach($arr as $a) {
print_r($a);
}
prints:
Array ( [0] => 4 [1] => 2 ) Array ( [0] => 0 [1] => 2 [2] => 4 [3] => 7 ) Array ( [0] => 7 [1] => 0 [2] => 2 [3] => 9 [4] => 4 )
EDIT:
Compute the ArrayScore for each array:
$arr0 = [0,2,4,7];
$arr1 = [7,0,2,9,4];
$arr2 = [4,2];
$arr = [$arr0,$arr1,$arr2];
$arrayScores = [];
//initialize the Scores with 0
foreach($arr as $a){
$arrayScores[] = 0;
}
//run through all arrays
for($i=0;$i<count($arr);$i++){
//with $j=$i+1, every combination is only checked once
for($j=$i+1; $j<count($arr);$j++){
if(count(array_intersect($arr[$j], $arr[$i])) == count($arr[$j])) {
$arrayScores[$i]++;
}
if(count(array_intersect($arr[$i], $arr[$j])) == count($arr[$i])){
$arrayScores[$j]++;
}
}
}
I am writing a script to compare the achievements of one player to another in a game. In each of the arrays the id and timestamp will match up on some entries. I have included a sample of one of the start of the 2 separate arrays:
Array
(
[0] => Array
(
[id] => 8213
[timestamp] => 1384420404000
[url] => http://www.wowhead.com/achievement=8213&who=Azramon&when=1384420404000
[name] => Friends In Places Higher Yet
)
[1] => Array
(
[id] => 6460
[timestamp] => 1384156380000
[url] => http://www.wowhead.com/achievement=6460&who=Azramon&when=1384156380000
[name] => Hydrophobia
)
I want to find all of the array items where the id and timestamp match. I have looked into array_intersect but I don't think this is what I am looking for as it will only find items when the entries are identical. Any help much appreciated.
You may use array_intersect_assoc function.
Try something like this:
<?php
$key_match = Array();
//Loop first array
foreach($array as $key => $element){
//Compare to second array
if($element == $array2[$key]){
//Store matching keys
$key_match[] = $key;
}
}
?>
$key_match will be an array with all matching keys.
(I'm at work and havn't had time to test the code)
Hope it helps
EDIT:
Fully working example below:
<?php
$a1["t"] = "123";
$a1["b"] = "124";
$a1["3"] = "125";
$a2["t"] = "123";
$a2["b"] = "124";
$a2["3"] = "115";
$key_match = Array();
//Loop first array
foreach($a1 as $key => $element){
//Compare to second array
if($element == $a2[$key]){
//Store matching keys
$key_match[] = $key;
}
}
var_dump($key_match);
?>
If you want to go on an exploration of array callback functions, take a look at array_uintersect. It's like array_intersect except you specify a function to use for the comparison. This means you can write your own.
Unfortunately, you need to implement a function that returns -1, 0 or 1 based on less than, same as, greater than, so you need more code. But I suspect that it'll be the most efficient way of doing what you're looking for.
function compareArrays( $compareArray1, $compareArray2 ) {
if ( $compareArray1['id'] == $compareArray2['id'] && $compareArray1['timestamp'] == $compareArray2['timestamp'] ) {
return 0;
}
if ( $compareArray1['id'] < $compareArray2['id'] ) {
return -1;
}
if ( $compareArray1['id'] > $compareArray2['id'] ) {
return 1;
}
if ( $compareArray1['timestamp'] < $compareArray2['timestamp'] ) {
return -1;
}
if ( $compareArray1['timestamp'] > $compareArray2['timestamp'] ) {
return 1;
}
}
var_dump( array_uintersect( $array1, $array2, "compareArrays") );