Find total year spans in an array with gaps - php

I need to draw a stacked bar graph for this array which should have 2 bars separated with a white-space of 2 years span (from year 1998 to 2000)
The Problem:
the first bar should be like,
*1998-1997* - *2 years gap* - *2000-2008*
The bars should merge shorter year-spans within like it did in taking 2000 from array0 and 2008 from array 1
Array
(
[comp_name] => C++
[parent_cat_name] => Information Technology
[sub_cat_name] => Programming
[total_years] => 6
[last_year] => 2006
[start_year] => 2000
)
Array
(
[comp_name] => .NET
[parent_cat_name] => Information Technology
[sub_cat_name] => Programming
[total_years] => 7
[last_year] => 2008
[start_year] => 2001
)
Array
(
[comp_name] => API
[parent_cat_name] => Information Technology
[sub_cat_name] => Programming
[total_years] => 1
[last_year] => 1998
[start_year] => 1997
)

You want to merge two array items, if they are adjacent according to some condition AND have some equality condition on some other fields.
You might do:
for(;;)
{
$merge = array();
$n = count($data);
for ($i = 0; empty($merge) && $i < $n-1; $i++)
{
for ($j = $i+1; empty($merge) && $j < $n; $j++)
{
// Are $i and $j congruent?
if ($data[$i]['parent_cat_name'] != $data[$j]['parent_cat_name'])
continue;
if ($data[$i]['sub_cat_name'] != $data[$j]['sub_cat_name'])
continue;
// Are $i and $j adjacent?
if ($data[$i]['last_year']+1 == $data[$j]['start_year'])
{
$merge = array($i, $j);
break;
}
if ($data[$j]['last_year']+1 == $data[$i]['start_year'])
$merge = array($j, $i);
break;
}
// They are congruent but not adjacent, try the next
}
}
// If we get to the end and find nothing mergeable, exit.
if (empty($merge))
break;
list($i, $j) = $merge;
// We add $j to $i
$data[$i]['last_year'] = $data[$j]['last_year']
$data[$i]['total_years'] += $data[$j]['total_years']
// We destroy $j
unset($data[$j]);
// Dirty renumber
$data = array_values($data);
// Now data has been modified, let's do this again.
}

Related

Push the output of a for loop into an array

I am trying to push the output of a for loop into an array but I am not being able to do so. Following is the code that I have written:
<?php
$n = 14;
for ($i = 2; $i <= $n; $i++)
{
for ($j = 2; $j <= $n; $j++)
{
if ($i%$j == 0) // if remainder of $i divided by $j is equal to zero, break.
{
break;
}
}
if ($i == $j) //
{
$form = $i;
//echo $form;
$numArray = array();
array_push($numArray, $form); // Here I am trying to push the contents from the `$form` variable into the `$numArray`
print_r($numArray);
}
}
?>
The output that I obtain through this is:
Array ( [0] => 2 ) Array ( [0] => 3 ) Array ( [0] => 5 ) Array ( [0] => 7 ) Array ( [0] => 11 ) Array ( [0] => 13 )
Here, we see that the array index basically remains the same, so it has no scope for future use. So, how can I make this seem like as shown below:
Array ( [0] => 2 ) Array ( [1] => 3 ) Array ( [2] => 5 ) Array ( [3] => 7 ) Array ( [4] => 11 ) Array ( [5] => 13 )
Please note that, $n in the code can be any number less than 101 and greater than 1. Thank you for your precious time put into reading and trying to helping me out. :)
The $numArray should be declared once, not every time in the loop. And you can simply add value to the array by using expression like: $numArray[] = $i;
Try this code:
<?php
$numArray = array();
$n = 14;
for ($i = 2; $i <= $n; $i++) {
for ($j = 2; $j <= $n; $j++) {
if ($i % $j == 0) { // if remainder of $i divided by $j is equal to zero, break.
break;
}
}
if ($i == $j) {
$numArray[] = $i;
}
}
print_r($numArray);

How to remove similar entries from array php

So i have array like this and sometimes it has very similar entries:
Array
(
[0] => greys anatomy
[1] => element 3d
[2] => interstellar
[3] => monster ball
[4] => scorpion
[5] => taken 3
[6] => the flash
[7] => wild card
[8] => big bang theory
[9] => the big bang theory
[10] => fredrik kempe vincero
[11] => fredrik kempe vicero
)
I would like to remove similar entries that are longer ones. So for example in this array: [9] => the big bang theory and [10] => fredrik kempe vincero entries should be removed. as they are similar to 8th and 11th entry, but longer.
EDIT:
So if anyone needs, I made working solution out of two answers below:
function check_similar($first, $second)
{
similar_text($first, $second, $percent);
if ($percent >= 80) { //needed percent value
return true;
}
else {
return false;
}
}
for ($i = 0; $i < count($array); $i++) {
for ($j = $i; $j < count($array); $j++) {
if ($j > $i && check_similar($array[$i],$array[$j]) == true) {
$array[$j] = null;
}
}
}
// filter array to remove null values and reindex
$array = array_values(array_filter($array));
print_r($array);
String similarity is a very difficoult problem that cannot be solved easily. There are several complex approaches, but none can be effective as if it was made by a human being.
Take a look on php soundhex and levenshtein which could be an easy solution for your particular case.
In any case, given a custom function that defines or not if a string is similar to another, to make your array unique you have to do something like:
// set to null all subsequent similar strings
for ($i = 0; $i < count($array); $i++) {
for ($j = $i; $j < count($array); $j++) {
if ($j > $i && similar($array[$i],$array[$j])) {
$array[$j] = null;
}
}
}
// filter array to remove null values
$array = array_filter($array);
Take a look at the similar_text function.
similar_text('the big bang theory','big bang theory', $percent);
echo $percent; // 88%
This is obviously more difficult than it seems, but can do this check while making this array.
See this link for an alternate implementation.

Sorting an multidimension array using usort fails

I tried to use custom-made usort funciton. when I loaded 5 cell array this runned over 30 seconds and then threw a fatal error.
I tried to find if I've been made an infinite loop but didn't founded it.
array:
Array ( [0] => Array ( [Name] => iPhone 5s 32 GB [Price] => 0 [Description] => A new Apple Product [Image_URL] => [Business_ID] => 6 [Keywords] => ["iPhone","iPhone 5s","Apple","32 GB"] ) [1] => Array ( [Name] => iPhone 4s 32 G [Price] => 300 [Description] => Apple iPhone 4S [Image_URL] => [Business_ID] => 6 [Keywords] => ["iPhone 4S","iPhone","Apple","32 GB"] ) )
search:
$searchTerm = "iphone 5s";
code:
if (!empty($searchTerm)) {
$searchTermWords = explode(" ", $searchTerm);
usort($products, function($a, $b) use ($searchTermWords) {
$aArr = explode(" ", $a['Name']);
$bArr = explode(" ", $b['Name']);
$aKeywords = $a['Keywords'];
$bKeywords = $b['Keywords'];
//todo: explode description too.
$aCount = 0;
$bCount = 0;
for ($i = 0; $i < $searchTermWords; $i++) {
for ($j = 0; $j < $aKeywords; $j++) {
if (strpos($aKeywords[$j], $searchTermWords[$i]) !== false)
$aCount++;
}
for ($j = 0; $j < $aArr; $j++) {
if ($aArr[$j] == $searchTermWords[$i])
$aCount++;
}
for ($j = 0; $j < $bKeywords; $j++) {
if (strpos($bKeywords[$j], $searchTermWords[$i]) !== false)
$bCount++;
}
for ($j = 0; $j < $bArr; $j++) {
if ($bArr[$j] == $searchTermWords[$i])
$bCount++;
}
}
return $bCount - $aCount;
});
}
Error (after 30 seconds):
Fatal error: Maximum execution time of 30 seconds exceeded in /home/itay/public_html/tester.php(30) : eval()'d code on line 94
if it's imprtant for some reason everything is made from eval() function.
You get the Fatal Error because your script doesn't exit properly. There is a For loop that runs infinitly.
Your for() loops are checked against the elements itself and not the number of elements. Are you trying to loop for the number of element in the array ? If so, try to use the count($array) to return the number of elements in the array. Then use that count to loop using the foreach.

Checking if a number in an array divides another number in the same array

What I need to accomplish is,
I have an array, 2 3 4 5 6 7 8 9 10
I need to check if any numbers in the array divides any other number in the array perfectly. (%=0) If yes, unset the the number.
Its over my head and I cant get it working and everything I tried gives me infinite loops and its making me ill. (lol)
I am not including any codes, because all I could come up with is a nested forloop which doesnt work :(
So here is a sample :
Input array :2 3 4 5 6 7 8
Output = 5 6 7 8
Any idea guys?
UPDATE:
Cracked the nut myself with bit more debugging. (Incase if that can be helpful for someone in future.)
// use array_unique, array_values and $size = sizeof($array)
for ($i = 0; $i < $size; $i++)
{
for ($j = $size - 1; $j > $i; $j--)
if ($numbers[$j] % $numbers[$i] == 0)
{
unset($numbers[$i]);
break;
}
}
I will not do this in real code, just because I think you want to do that yourself.
LoopA iterating the intput array:
LoopB iterating the input array:
check division of loopA value and loopB value, and add the value of loopA to a new array accordingly
End loopB
End loopA
Print the new array
Note: This is not complete, but it certainly should give you a start on how to continue.
For sorted ordered number
$arr = array(2,3,4,5,6,7,8,9,10,11,12,13,14);
$half_c = ceil(count($arr)/2) - 1;
$result_array = array_slice($arr, $half_c);
Edit: For random array you can cut half again, and iterate only first part of array. Prime number theory also can help to write faster algorithm for first part of array.
How about:
$arr = range(2,20);
$size = count($arr);
for ($i=0; $i<$size; $i++) {
for ($j=$size-1; $j>$i; $j--) {
if ($arr[$j]%$arr[$i]) continue;
unset($arr[$i]);
break;
}
}
print_r($arr);
output:
Array
(
[9] => 11
[10] => 12
[11] => 13
[12] => 14
[13] => 15
[14] => 16
[15] => 17
[16] => 18
[17] => 19
[18] => 20
)
Try this:
for($i = 0; $i < count($arr); $i++)
{
for($j = 0; $j < count($arr); $j++)
{
if($arr[$i] != $arr[$j] && $arr[$i] % $arr[$j] === 0)
{
unset($arr[$j);
break;
}
}
}

PHP remove similar arrays based on several associations in an associative array

I have this type of associative array.
Array
(
[0] => Array
(
[bookedArea] => Comp Pool
[laneBooked] => 1
[paidBy] => Edmonton Aurora Synchronized Swim Club
[startTime24hr] => 16:00
[finishTime24hr] => 18:00
)
[1] => Array
(
[bookedArea] => Comp Pool
[laneBooked] => 2
[paidBy] => Edmonton Aurora Synchronized Swim Club
[startTime24hr] => 16:00
[finishTime24hr] => 18:00
)
[2] => Array
(
[bookedArea] => Comp Pool
[laneBooked] => 3
[paidBy] => Keyano Swim Club
[startTime24hr] => 16:00
[finishTime24hr] => 18:00
)
)
I would like to make a new array removing similar entries depending on several associations. startTime24hr, finishTime24hr bookedArea & paidBy if all 4 aren't the same then it shouldn't be removed. Plus I would like to capture the first and last lanes in the new associative array.
Array
(
[0] => Array
(
[bookedArea] => Comp Pool
[firstLaneBooked] => 1
[lastLaneBooked] => 2
[paidBy] => Edmonton Aurora Synchronized Swim Club
[startTime24hr] => 16:00
[finishTime24hr] => 18:00
)
[2] => Array
(
[bookedArea] => Comp Pool
[firstLaneBooked] => 3
[lastLaneBooked] => 3
[paidBy] => Keyano Swim Club
[startTime24hr] => 16:00
[finishTime24hr] => 18:00
)
)
I found this which would help me filter with only one association. However I need 3 more.
$copy = $array; // create copy to delete dups from the array you wish to filter from
$newFilteredArray = array(); // new filtered array.
$item1 = 'startTime24hr'; // the association you want to filter with.
for( $i=0; $i<count($array); $i++ ) {
if ( in_array( $array[$i][$item1], $newFilteredArray ) ) {
unset($copy[$i]);
}
else {
$newFilteredArray [] = $array[$i][$item1]
}
}
print_r($copy);
Edit ----
Thank you Alexander for helping me get the iterations correct.
I have been struggling with inserting into my filtered array the start and finish lanes. I have commented out my attempts to make it work. When its uncommented I get: Notice: Undefined index: startTime24hr and it seems like its in some infinite loop.
But if you comment my stuff no Notices. Can anyone help with this?
function array_push_assoc($array, $key, $value){
$array[$key][] = $value;
return $array;
}
$CPfilteredArray = array();
$lanes = 0;
for($i = 0; $i < count($compPoolArray); $i++) {
$add = true;
// $lanesAdded = false;
// $lanes = $lanes + 1;
// $startLane = $compPoolArray[$i]["laneBooked"];
for($j = 0; $j < count($CPfilteredArray); $j++) {
if(($compPoolArray[$i]["startTime24hr"] === $CPfilteredArray[$j]["startTime24hr"])
&& ($compPoolArray[$i]["finishTime24hr"] === $CPfilteredArray[$j]["finishTime24hr"])
&& ($compPoolArray[$i]["bookedArea"] === $CPfilteredArray[$j]["bookedArea"])
&& ($compPoolArray[$i]["paidBy"] === $CPfilteredArray[$j]["paidBy"])) {
$add = false;
// $lanes = $lanes + 1;
// $lanesAdded = True;
}
}
if($add) {
$CPfilteredArray[] = $compPoolArray[$i];
// if ($lanesAdded){
// $lastLane = $startLane + $lanes;
// $CPfilteredArray[$i] = array_push_assoc($CPfilteredArray, 'firstLane', $startLane);
// $CPfilteredArray[$i] = array_push_assoc($CPfilteredArray, 'lastLane', $lastLane);
// }
// else {
// $CPfilteredArray[$i] = array_push_assoc($CPfilteredArray, 'firstLane', $startLane);
// $CPfilteredArray[$i] = array_push_assoc($CPfilteredArray, 'lastLane', $startLane);
// }
}
}
Two loop cycles do the job.
$filteredArray = array();
for($i = 0; $i < count($array); $i++) {
$add = true;
for($j = 0; $j < count($filteredArray); $j++) {
if(($array[$i]["startTime24hr"] === $filteredArray[$j]["startTime24hr"])
&& ($array[$i]["finishTime24hr"] === $filteredArray[$j]["finishTime24hr"])
&& ($array[$i]["bookedArea"] === $filteredArray[$j]["bookedArea"])
&& ($array[$i]["paidBy"] === $filteredArray[$j]["paidBy"])) {
$add = false;
}
}
if($add) $filteredArray[] = $array[$i];
}
The resulting array called $filteredArray contains the filtered elements.
I know it doesn't really answer (not allowed to comment yet...) your question but if you're retrieving data from db, you could use a query to retrive grouped values.
It could look sth like this (pseudo-SQL)
SELECT
bookedArea
,paidBy
,startTime24hr
,finishTime24hr
,MIN(laneBooked)
,MAX(laneBooked)
FROM
reservation -- ??
WHERE
--condition
GROUP BY
bookedArea
,paidBy
,startTime24hr
,finishTime24hr
If you do know what elements you use to merge array value you may also use a hashmap to do the merge on insertion. So once you add an element to the array you create a hash over
$bookings = array();
$hash = md5($arr['bookedArea'] . $arr['paidBy'] . $arr['startTime24hr'] . $arr['finishTime24hr']);
if ( array_key_exists($hash, $bookings) ){
//add just another lane to the booking
}
else{
//create a new booking entry
}
that way your code may be even more efficient.
This may also work: (You can replace the serialize function to only serialize selected elements)
<?php
$arr=array(
0=>array("a"=>1, "b"=>"hello"),
1=>array("a"=>2, "b"=>"hellooo"),
2=>array("a"=>1, "b"=>"hello"),
);
function removeDuplicates( &$arr ){
$index=array();
$result=array();
foreach ($arr as $key=>$val){
$k=serialize($val);
if(!isset($index[$k])){
$index[$k]=$key;
$result[$key]=$val;
}
}
return $result;
}
$result=removeDuplicates($arr);
print_r($arr);
print '<br>';
print_r($result);
?>

Categories