I'm trying to sort an array in PHP. The array is names in the even indices and times (MM:SS.XX).
Array ( [0] => Emma Hogan [1] => 09:12.55 [2] => Bob Harrison [3] => 12:00.15 [4] => Dave Haenze [5] => 10:00.98 [6] => Tau Newman [7] => 07:05.15 [8] => Cai Jones [9] => 44:15.59 )
What I want it to do is grab the every other element (the times) and sort the array by shortest time to longest. My code for it looks like this:
for($i=1;$i<$arrlength;$i+=2) {
$j = $i;
while (($j>0)&&($array[($j-2)] > $array[$j])){
$temp = $array[$j];
$array[$j] = $array[($j-2)];
$array[($j-2)] = $temp;
$temp2 = $array[($j+1)];
$array[($j+1)] = $array[($j-1)];
$array[($j-1)] = $temp;
$j = $j - 2;
}
}
However, the output it returns looks like this:
Emma Hogan
07:05.15
07:05.15
09:12.55
Bob Harrison
10:00.98
10:00.98
12:00.15
Dave Haenze
44:15.59
What am I doing wrong? What do I need to change to make it sort properly?
You've indicated that you can change the array format. If so consider the following:
$array = array ( 'Emma Hogan' => '09:12.55' );
asort($array); //or arsort()
Or:
$array = array ( '09:12.55' => 'Emma Hogan' );
ksort($array); //or krsort()
As you can see your array layout makes little sense for what you want to accomplish. I sugest fixing that first, instead of bending the head and trying to work on bad data structure. I.e.:
$tmp = array();
for($i=0; $i<count($srcArray); $i+=2) {
$tmp[$srcArray[i]] = $srcArray[$i+1];
}
and then you can sort $tmp using usort(). Or even better, you can convert your times to numeric value and then just user ordinary sort() to do the job.
Related
I have an array as so:
$diff_date_results =
Array (
[0] => Array ( [differential] => 7.7 [date] => 2012-12-30 )
[1] => Array ( [differential] => 8.2 [date] => 2012-12-31 )
[2] => Array ( [differential] => 9.9 [date] => 2013-01-03 )
)
I would like to extract all values from the differential key of each of the inner arrays to use the array_sum function on the newly created array.
I have this, which draws out the three numbers for me, but I get php errors for each number as an undefined index. (Notice: Undefined index: 7.7 in C:\wamp\www\jquery\test.php on line 55)
My code thus far is as follows:
$diff_results = array();
foreach($diff_date_results as $entry){
$diff_results[$entry['differential']];
}
print_r($diff_results);
I am sure it is simple, I have been screwing around with it for way too long now, any help would be wonderful!
Thanks.
$diff_results = array();
foreach($diff_date_results as $entry){
$diff_results[] = $entry['differential'];
}
//just for displaying all differential
print_r($diff_results);
Now, you can use array_sum on $diff_results.
Moreover, if you want to have sum then you can use below method too.
$diff_results = "";
foreach($diff_date_results as $entry){
$diff_results = $diff_results + $entry['differential'];
}
//$diff_results will have sum of all differential
echo $diff_results;
$diff_results = array_map($diff_date_results,
function($entry) { return $entry['differential']; });
Do it like this:
$diff_results = array();
foreach($diff_date_results as $key => $entry){
$diff_results[] .= $entry['differential']];
}
print_r($diff_results);
Thanks.
$diff_date_results = array (
0 => array ( 'differential'=> 7.7, 'date' => 20),
1 => Array ( 'differential' => 8.8, 'date' => 20 ),
2 => Array ( 'differential' => 9.8 ,'date' => 20 ),
);
$value_differential=array();
foreach( $diff_date_results as $key=>$value){
print_r($value);
$value_differential[]=$value['differential'];
}
print_r(array_sum($value_differential));
For anyone stumbling across this question as I have, the best solution in my opinion is a working version of Barmars as below:
$diff_results = array_map(function($entry)
{
return $entry['differential'];
},
$diff_date_results);
it's a more elegant, 1 line solution (which I've expand to 5 lines for readability).
I have a large array of scraped names and prices similar to the following:
Array([0] => apple3 [1] => £0.40 [2] => banana6 [3] => £1.80 [4] => lemon [5] => grape [6] => pear5 [7] => melon4 [8] => £2.32 [9] => kiwi [10] => £0.50)
I would like to remove the fruit names that are not immediately followed by a price. In the above example this would remove: [4] => lemon [5] => grape [6] => pear5 resulting in the following output:
Array([0] => apple3 [1] => £0.40 [2] => banana6 [3] => £1.80 [7] => melon4 [8] => £2.32 [9] => kiwi [10] => £0.50)
If the array needs to be converted to a string in order for me to do this that is not a problem, nor is adding values between the array items in order to aid with regex searches. I have so far been unable to find the correct regular expression to do this using preg_match and preg_replace.
The most important factor is the need to maintain the sequential order of the fruits and prices in order for me at a later stage to convert this into an associative array of fruits and prices.
Thanks in advance.
Why involve regular expressions? This is doable with a simple foreach loop wherein you iterate over the array and remove names that follow names:
$lastWasPrice = true; // was the last item a price?
foreach ($array as $k => $v) {
if (ctype_alpha($v)) {
// it's a name
if (!$lastWasPrice) {
unset($array[$k]); // name follows name; remove the second
}
$lastWasPrice = false;
}
else {
// it's a price
$lastWasPrice = true;
}
}
The following code does both of your tasks at once: getting rid of the fruit without value and turning the result into an associative array of fruits with prices.
$arr = array('apple', '£0.40', 'banana', '£1.80', 'lemon', 'grape', 'pear', 'melon', '£2.32', 'kiwi', '£0.50' );
preg_match_all( '/#?([^£][^#]+)#(£\d+\.\d{2})#?/', implode( '#', $arr ), $pairs );
$final = array_combine( $pairs[1], $pairs[2] );
print_r( $final );
First, the array is converted to a string, separated by '#'. The regex captures all groups of fruits with prices - each stored as a separate subgroup in the result. Combining them into an associative array is a single function call.
Something like this might help you
$array = ...;
$index = 0;
while (isset($array[$index + 1])) {
if (!is_fruit($array[$index + 1])) {
// Not followed by a fruit, continue to next pair
$index += 2;
} else {
unset($array[$index]); // Will maintain indices in array
$index += 1;
}
}
Not tested though. Also, you need to create the function is_fruit yourself ;)
Without reformatting it, I don't think you can do it with preg_match or preg_replace-- maybe, but nothing is coming to mind.
What is creating that array? If possible, I would alter it to look more like:
Array([apple] => £0.40 [banana] => £1.80 [lemon] => [grape] => '' [pear ] => '' [melon => £2.32 [kiwi] => £0.50)
Then array_filter($array) is all you'd need to clean it up. If you can't alter the way the original array is created I'd lean towards creating key/value array out of the original.
Try replacing the pattern ** => ([a-zA-Z])** with ** => £0.00 $1**
Basically searching for the context where there is null price and inserting zero pounds.
Hope this helps.
Good luck
Simply do this :
<?php
for($i=0;$i<count($my_array);$i++)
{
if($my_array[$i+1]value=="")
unset($my_array[$i])
}
?>
assume $a is your array.
function isPrice($str) {
return (substr($str, 0, 1) == '£');
}
$newA = array();
for($i=0;$i<count($a);$i++) {
if( isPrice($a[$i]) != isPrice($a[$i+1]) ){
$newA[] = $a[$i];
}
}
I want to check only the value [id] for duplicates, and remove all keys where this "field" [id] is a duplicate.
Example: If I have numbers 1,2,1. I want the result to be 2, not 1,2. And criteria for duplicates is determined only by checking [id], not any other "field".
Original array:
Array
(
[0] => Array
(
[name] => John
[id] => 123
[color] => red
)
[1] => Array
(
[name] => Paul
[id] => 958
[color] => red
)
[2] => Array
(
[name] => Jennifer
[id] => 123
[color] => yellow
)
)
The result I want:
Array
(
[0] => Array
(
[name] => Paul
[id] => 958
[color] => red
)
)
I agree with everyone above, you should give us more information about what you've tried, but I like to code golf, so here's a completely unreadble solution:
$new_array = array_filter($array, function($item) use (&$array){
return count(array_filter($array, function($node) use (&$item){
return $node['id'] == $item['id'];
})) < 2;
});
This should be fairly easy to accomplish with a couple of simple loops:
set_time_limit(0); // Disable time limit to allow enough time to process a large dataset
// $items contains your data
$id_counts = array();
foreach ($items as $item) {
if (array_key_exists($item['id'], $id_counts)) {
$id_counts[$item['id']]++;
} else {
$id_counts[$item['id']] = 1;
}
}
for ($i = count($items); $i >= 0; $i--) {
if ($id_counts[$items[$i]['id']] > 1) {
array_splice($items, $i, 1);
}
}
Result:
Array
(
[0] => Array
(
[name] => Paul
[id] => 958
[color] => red
)
)
While there are neater ways to do it, one advantage of this method is you're only creating new arrays for the list of ids and duplicate ids and the array_splice is removing the duplicates from the original array, so memory usage is kept to a minimum.
Edit: Fixed a bug that meant it sometimes left one behind
This is a very basic approach to the answer and I am sure there are much better answers however I would probably start by doing it the way I would on paper.
I look at the first index, check its value. Then I go through every other index making note of their index if the value is the same as my originally noted value. Once I have gone through the list if I have more than one index with that particular value I remove them all (starting with the highest index, so as to not affect indexes of the others while deleting).
Do this for all other indexes till you reach the end of the list.
It is long winded but will make sure it removes all values which have duplicates. and leaves only those which originally had no duplicates.
function PickUniques(array $items){
// Quick way out
if(empty($items)) return array();
$counters = array();
// Count occurences
foreach($items as $item){
$item['id'] = intval($item['id']);
if(!isset($counters[$item['id']])){
$counters[$item['id']] = 0;
}
$counters[$item['id']]++;
}
// Pop multiples occurence ones
foreach($counters as $id => $occurences){
if($occurences > 1){
unset($counters[$id]);
}
}
// Keep only those that occur once (in $counters)
$valids = array();
foreach($items as $item){
if(!isset($items[$item['id']])) continue;
$valids[$item['id']] = $item;
}
return $valids;
}
Try this one :)
Can someone please put me out of my misery and explain why I'm missing the middle value when I try to push the results of a preg_match into another array? It's either something silly or a vast gap in my understanding. Either way I need help. Here is my code:
<?php
$text = 'The group, which gathered at the Somerfield depot in Bridgwater, Somerset,
on Thursday night, complain that consumers believe foreign meat which has been
processed in the UK is British because of inadequate labelling.';
$word = 'the';
preg_match_all("/\b" . $word . "\b/i", $text, $matches, PREG_OFFSET_CAPTURE);
$word_pos = array();
for($i = 0; $i < sizeof($matches[0]); $i++){
$word_pos[$matches[0][$i][0]] = $matches[0][$i][1];
}
echo "<pre>";
print_r($matches);
echo "</pre>";
echo "<pre>";
print_r($word_pos);
echo "</pre>";
?>
I get this output:
Array
(
[0] => Array
(
[0] => Array
(
[0] => The
[1] => 0
)
[1] => Array
(
[0] => the
[1] => 29
)
[2] => Array
(
[0] => the
[1] => 177
)
)
)
Array
(
[The] => 0
[the] => 177
)
So the question is: why am I missing the [the] => 29? Is there a better way? Thanks.
PHP arrays are 1:1 mappings, i.e. one key points to exactly one value. So you are overwriting the middle value since it also has the key the.
The easiest solution would be using the offset as the key and the matched string as the value. However, depending on what you want to do with the results a completely different structure might be more appropriate.
First you assign $word_pos["the"] = 29 and then you OVERWRITE IT with $word_pos["the"] = 177.
You don't overwrite The because indexes are case sensitive.
So maybe use an array of objects like this:
$object = new stdClass;
$object->word = "the"; // for example
$object->pos = 29; // example :)
and assign it to an array
$positions = array(); // just init once
$positions[] = $object;
alternatively you can assign an associative array instead of the object, so it would be like
$object = array(
'word' => 'the',
'pos' => 29
);
OR assign the way you do, but instead of overwriting, just add it to an array, like:
$word_pos[$matches[0][$i][0]][] = $matches[0][$i][1];
instead of
$word_pos[$matches[0][$i][0]] = $matches[0][$i][1];
so you get something like:
Array
(
[The] => Array
(
[0] => 0
)
[the] => Array
(
[0] => 29
[1] => 177
)
)
Hope that helps :)
What is happening actually :
when i=0,
$word_pos[The] = 0 //mathches[0][0][0]=The
when i=1
$word_pos[the] = 29
when i=3
$word_pos[the] = 177 //here this "the" key overrides the previous one
//so your middle 'the' is going to lost :(
Now an array based solution can be like this :
for($i = 0; $i < sizeof($matches[0]); $i++){
if (array_key_exists ( $matches[0][$i][0] , $word_pos ) ) {
$word_pos[$matches[0][$i][0]] [] = $matches[0][$i][1];
}
else $word_pos[$matches[0][$i][0]] = array ( $matches[0][$i][1] );
}
Now if you dump $word_pos the output should be :
Array
(
[The] => Array
(
[0] => 0
)
[the] => Array
(
[0] => 29 ,
[1] => 177
)
)
Hope that helps.
Reference : array_key_exist
Hi there I'm a bit confused on how I go about this. Any help would be greatly appreciated.
I have the following code.
$worms_level1 = $this->catch_the_worm_model->get_worms_by_level(1);
$captured_worms = array();
for ($i = 0; $i < $num_worms; $i++)
{
$captured_worms[$i] = array_rand($worms_level1);
}
return $captured_worms;
The $worms_level1 multidimensional array takes the following format:
Array ( [0] => Array ( [worm_id] => 1
[worm_name] => Verm
[worm_description] => The most common verm, not a huge threat but a great nuisance.
[worm_level] => 1
[worm_value] => 1 )
[1] => Array ( [worm_id] => 2
[worm_name] => Vermichav
[worm_description] => Vermichav loves a scuffle. He's been known to spit in Wormcatcher's eyes and inflict pain by cigarette burns.
[worm_level] => 1 [worm_value] => 1 )
)
At the minute the code is successful at selecting random arrays and saving them to a new array eg
Array ( [0] => 1 [1] => 1 )
but I also want the descendent arrays to be saved to the new array.
How about:
$captured_worms=array();
$howmany=20;
do{
$howmany-=count($captured_worms);//decreases $howmany by the number we already grabbed
shuffle($multiarray); //reorder the multiarray randomly
$captured_worms=array_slice($multiarray,0,$howmany);//get as many elements as you want
} while(count($captured_worms)<$howmany); //ensures at least $howmany