I'm trying to multisort a DB array based on the users status. Those with Status = 1 go at the top, those with Status = 0 go at the bottom of the array. I thought I had it working but it just stopped today with the addition of new rows to the DB.
uasort($ven, function ($a, $b) { return $a['v_status'] == '1' ? false : true; });
It's a simple DB array from MySQL:
Array (
[0] => array(
[name] => '',
[v_status] => 0
[1] => array(
[name] => '',
[v_status] => 1
)
As mentioned in comments to my other answer, splitting the array into active/inactive arrays could be a better solution than sorting.
$items = array(
array('name' => 'active1', 'active' => '1'),
array('name' => 'inactive1', 'active' => '0'),
array('name' => 'active2', 'active' => '1'),
array('name' => 'inactive2', 'active' => '0'),
array('name' => 'inactive3', 'active' => '0'),
array('name' => 'active3', 'active' => '1'),
array('name' => 'inactive4', 'active' => '0'),
);
$active = array_filter($items, function($item){ return $item['active'] == '1'; });
echo '<pre>' . print_r($active,true);
// You could filter again here, not sure which would be quicker,
// but my guess would be the array_diff method (which also ensures
// that no items get filtered out by both filters)
$inactive = array_diff_key($items, $active);
echo '<pre>' . print_r($inactive,true);
uasort expects the callback to return a positive integer if $a should be above $b, a negative integer if $b should be above $a or 0 if they are equal.
This is why despite there only being 2 options Jon's suggestion return $b['v_status'] - $a['v_status']; is correct.
In your case if at some point during the sort $a[v_status] = 0 and $b[v_status] = 1 the function looks at $a[v_status], returns false, which equates to 0 and the algorithm (quick sort I think) treats them as equal and therefore leaves them in their current order.
See PHP: usort for reference, which expects a similar callback.
Related
I have a multidimensional array as follows, which is a PHP array of shoe sizes and their conversions...
$size_array = array(
"M"=>array(
'6'=> array('uk'=>'6','eu'=>'39.5','us'=>'7'),
'6H'=> array('uk'=>'6.5','eu'=>'40','us'=>'7.5'),
'7'=> array('uk'=>'7','eu'=>'40.5','us'=>'8'),
'7H'=> array('uk'=>'7.5','eu'=>'41','us'=>'8.5'),
'8'=> array('uk'=>'8','eu'=>'42','us'=>'9'),
'8H'=> array('uk'=>'8.5','eu'=>'42.5','us'=>'9.5'),
'9'=> array('uk'=>'9','eu'=>'43','us'=>'10'),
'9H'=> array('uk'=>'9.5','eu'=>'44','us'=>'10.5'),
'10'=> array('uk'=>'10','eu'=>'44.5','us'=>'11'),
'10H'=> array('uk'=>'10.5','eu'=>'45','us'=>'11.5'),
'11'=> array('uk'=>'11','eu'=>'46','us'=>'12'),
'11H'=> array('uk'=>'11.5','eu'=>'46.5','us'=>'12.5'),
'12'=> array('uk'=>'12','eu'=>'47','us'=>'13'),
'12H'=> array('uk'=>'12.5','eu'=>'48','us'=>'13.5'),
'13'=> array('uk'=>'13','eu'=>'48.5','us'=>'14')
),
"F"=>array(
'3'=> array('uk'=>'3','eu'=>'35.5','us'=>'5'),
'3H'=> array('uk'=>'3.5','eu'=>'36','us'=>'5.5'),
'4'=> array('uk'=>'4','eu'=>'37','us'=>'6'),
'4H'=> array('uk'=>'4.5','eu'=>'37.5','us'=>'6.5'),
'5'=> array('uk'=>'5','eu'=>'38','us'=>'7'),
'5H'=> array('uk'=>'5.5','eu'=>'38.5','us'=>'7.5'),
'6'=> array('uk'=>'6','eu'=>'39','us'=>'8'),
'6H'=> array('uk'=>'6.5','eu'=>'39.5','us'=>'8.5'),
'7'=> array('uk'=>'7','eu'=>'40','us'=>'9'),
'7H'=> array('uk'=>'7.5','eu'=>'41','us'=>'9.5'),
'8'=> array('uk'=>'8','eu'=>'41.5','us'=>'10'),
'8H'=> array('uk'=>'8.5','eu'=>'42.5','us'=>'10.5'),
'9'=> array('uk'=>'9','eu'=>'43','us'=>'11'),
'9H'=> array('uk'=>'9.5','eu'=>'43.5','us'=>'11.5'),
'10'=> array('uk'=>'10','eu'=>'44','us'=>'12')
)
);
The array is part of a function that returns the conversions based on a supplied size and gender (i.e. SizeConvert('M','6') returns Array ([uk] => 6, [eu] => 39.5,[us] => 7)).
I want to extend the function to allow the passing of a value which will return the array results with any .5 values replaced with ½ (or ½) (i.e. SizeConvert('M','6','Y') returns Array ([uk] => 6, [eu] => 39½,[us] => 7))
How do I make str_replace (or a more appropriate command) iterate over the array and replace the values?
I've tried something like str_replace(".5", "½", $size_array) but I guess that's not working as it's only looking at the initial array, not the sub-arrays.
You are trying to apply this to a multidimensional array without real reason. If you have your SizeConvert function ready and returning a one dimensional array, simply apply the transformation before returning the value:
function SizeConvert(/* other parameters */, bool $convertOneHalf) {
$match = ... // your code to find the match
return $convertOneHalf
? str_replace('.5', '½', $match)
: $match;
}
Based on the boolean value of the parameter that dictates whether the conversion should be applied, we either return the modified or the unmodified result through the ternary.
Do not overthink it and use a for loop to loop through all the elements in the array and use an if...else... to check for 0.5
if($array[index]=="0.5") {
$array[index]="½";
} else {
$array[index]=str_replace(".5", "½", $array[index]);
}
I coded up a simple code, it's not exactly the answer to your question but u can use the logic behind it. The code below will change all the 0.5 in the array to 1⁄2 but since u already acquire the data, there is no need to have so much nested-loop, just 1 level of the loop to loop through all ur elements in your array is enough.
<?php
$size_array = array(
"M" => array(
'6' => array(
'uk' => '6',
'eu' => '39.5',
'us' => '7'
) ,
'6H' => array(
'uk' => '6.5',
'eu' => '40',
'us' => '7.5'
) ,
'7' => array(
'uk' => '7',
'eu' => '40.5',
'us' => '8'
)
) ,
"F" => array(
'3' => array(
'uk' => '3',
'eu' => '35.5',
'us' => '5'
) ,
'3H' => array(
'uk' => '3.5',
'eu' => '36',
'us' => '5.5'
) ,
'4' => array(
'uk' => '4',
'eu' => '37',
'us' => '6'
)
)
);
foreach ($size_array as $firstLevel)
{
foreach ($firstLevel as $secondLevel)
{
foreach ($secondLevelas $values)
{
if ($values== "0.5")
{
echo $values= "½";
}
else
{
echo $values= str_replace(".5", "½", $values);
}
}
}
}
?>
I'm pulling data from a csv and uploading it to a db, for some columns, only certain values should be inputted (or it'll break going through the rest of the system)
however users don't to write out the full input so will use "y" instead of "yes"
I wrote a function that takes an array of the possible inputs and what the correct output should be.
however, currently the array and function looks like this:
$this->acceptedInputMap = array (
'yes' => 'yes',
'y' => 'yes',
'true' => 'yes',
'no' => 'no',
'n' => 'no',
'false' => 'no',
'unknown' => 'unknown',
'unk' => 'unknown',
'' => 'unknown'
);
//these are in the parents class------------------------------------
protected function useAcceptedinput()
{
foreach ($this->columnData as $key => $element) {
if ($this->isExpectedInput($element)) {
$this->useMappedInput($key, $element);
} else {
$this->useColumnDefault($key);
}
}
}
protected function isExpectedInput($element)
{
return array_key_exists(strtolower($element), $this->acceptedInputMap);
}
protected function useColumnDefault($key)
{
$this->columnData[$key] = $this->defaultValue;
}
protected function useMappedInput($key, $element)
{
$this->columnData[$key] = $this->acceptedInputMap[strtolower($element)];
}
I wanted to change this to use a different structure:
$this->acceptedInputMap = array (
'yes' => array(
'yes',
'y',
'true'
),
'no' => array(
'no',
'n',
'false'
),
'unknown' => array(
'unknown',
'unk',
''
),
);
This is a lot clearer for future developers and would make it a lot easier to add more accepted inputs.
This also allows me to have the parent store some common acceted inputs, such as "yes", that can be pulled down for each column that requires it.
However, this is a 2d array, and attempting to find the value in the second dimension to map to the correct input is more computationally intensive.
Is the change worth it?
Also, in general, where do you draw the line on making it easier for the next dev, vs making it faster?
You could organize the original array to make it more readable without sacrificing performance by adding comments or blank lines:
$this->acceptedInputMap = array (
// yes --------
'yes' => 'yes',
'y' => 'yes',
'true' => 'yes',
// no ----------
'no' => 'no',
'n' => 'no',
'false' => 'no',
// unknown -----
'unknown' => 'unknown',
'unk' => 'unknown',
'' => 'unknown'
);
i have an array like this
$jartot = array(
0 => array(
'id_titik' => '1',
'distance' => '300',
'name_titik' => 'titik A',
),
1 => array(
'id_titik' => '2',
'distance' => '412',
'name_titik' => 'titik B',
),
2 => array(
'id_titik' => '3',
'distance' => '130',
'name_titik' => 'titik C',
),
);
i want to get value of min distance, and also get its id_titik.
i trying use array_column to get min value of distance,
echo min(array_column($jartot, 'distance'));
but how to get its id_titik at the same time?
You might first sort the array using usort by distance and then get the values from the first array:
usort($jartot, function($a, $b){
return $a['distance'] > $b['distance'];
});
echo $jartot[0]['id_titik']; // 3
echo $jartot[0]['distance']; // 130
echo $jartot[0]['name_titik']; // titik C
Demo
If there are multiple with the same distance you could use array_column to get the lowest value and use array_filter to filter the result where distance equals that value:
$min = min(array_column($jartot, 'distance'));
$results = array_filter($jartot, function($x) use ($min){
return $x['distance'] === $min;
});
Demo
I have an array with key and value pair. I'm building this array dynamically and below is the code.
$x[] = array('type_name' => $value->name,
'percentage'=> intval($percentage));
My intention is to get the maximum value and for that I do
max($x);
However it is returning the wrong value actually the lowest value. Following is my array. Any help would be awesome.
$x = array(
array(
'type_name' => 'type 1'
'percentage' => 10,
),
array(
'type_name' => 'type 2'
'percentage' => 15,
),
array(
'type_name' => 'type 3'
'percentage' => 45,
),
);
Thanks is advance.
From php max() documentation :
// Multiple arrays of the same length are compared from left to right
It means that if you want to compare "percentage" values first instead of "type_name" values, you'll have to change their order in the array.
So, you could build your array like this ("percentage" comes first) and it should work :
$x[] = array(
'percentage'=> intval($percentage),
'type_name' => $value->name
);
For example :
$x = array(
array(
'percentage' => 10,
'type_name' => 'type 1'
),
array(
'percentage' => 15,
'type_name' => 'type 2'
),
array(
'percentage' => 45,
'type_name' => 'type 3'
),
array(
'percentage' => 25,
'type_name' => 'type 4'
)
);
print_r(max($x));
Output :
Array
(
[percentage] => 45
[type_name] => type 3
)
Hope it helps.
You need to read how the max compares against different types of data. In your case, you are trying to compare against one of the array item i.e. percentage inside one of the item so the function max does not know to do this.
There is an example by Revo in the manual which shows you how to do this.
You are creating an array of arrays. max doesn’t know that your arrays should be compared by the 'percentage' key, so it can’t be used here.
Instead, find the maximum value yourself. For example, like this:
$maxPercentage = false;
foreach ($x as $item) {
if ($maxPercentage === false || $item['percentage'] > $maxPercentage) {
$maxPercentage = $item['percentage'];
}
}
Now, $maxPercentage will store maximum percentage. Of, if you want an item with maximum percentage, get it like this:
$maxPercentage = false;
$maxItem = false;
foreach ($x as $item) {
if ($maxPercentage === false || $item['percentage'] > $maxPercentage) {
$maxPercentage = $item['percentage'];
$maxItem = $item;
}
}
I have an array of data which contains associative array rows and I would like to sort them by price,date etc. This cannot be done via SQL as these values are not in a database - I simply have a large array with the following example data:
$data[0] = array(
'id' => '2',
'price' => '400.00',
'date' => '2012-05-21',
),
$data[1] = array(
'id' => '4',
'price' => '660.00',
'date' => '2012-02-21',
),
$data[2] = array(
'id' => '8',
'price' => '690.00',
'date' => '2012-01-21',
)
etc..................
How can I sort this variable based on a select box such as sort by price ASC/DESC and date ASC/DESC
Sorry if this is simple - I am just so used to doing it via SQL that my mind has gone blank in this case.
I think you may modify this function:
http://php.net/manual/en/function.sort.php#104464
You should use usort and define a function which sorts based on the key you want.
Check out http://www.php.net/manual/en/function.usort.php examples 2 and 4.
Below sample code will sort it by id.
$capitals = array(
array(
'id' => '2',
'price' => '400.00',
'date' => '2012-05-21',
),
array(
'id' => '1',
'price' => '660.00',
'date' => '2012-02-21',
),
array(
'id' => '0',
'price' => '690.00',
'date' => '2012-01-21',
)
);
function cmp($a, $b)
{
return strcmp($a["id"], $b["id"]);
}
usort($capitals, "cmp");
print_r($capitals);
Use usort:
function sortBySubKey(&$array, $key)
{
return usort($array, create_function('$a,$b', 'if ($a["'.$key.'"] == $b["'.$key.'"]) return 0; return ($a["'.$key.'"] < $b["'.$key.'"]) ? -1 : 1;'));
}
You should make sure that your array holds valid values in the sense of this arithmetical comparision (<), eg. you should probably pass date as a unix timestamp for this, price as a float and so on...