I currently have a 2 dimensional array that has data like this :
X X X X
X X X X
X X X
X X X X
X X X X
X X X X X
X marks a cell that has data, blank means its empty.
I having been pulling my hair for the last hour trying to figure out how to count what I call "holes".
It's basically a cell with empty data between two cells having data.
So by order you can see the cols have respectively 2, 0, 2, 0, 0 holes from left to right.
My function needs to return the total holes, so for this case 4.
Currently I have done this really close but my function is counting the 2 first cells on the 4th col which is wrong and I can't figure out how to account for that.
Here is my actual code :
public function countHoles(){
$total = 0;
for($i=0; $i<5; $i++){
$counting = false;
$passed = false;
for($j=0; $j<10; $j++){
if(count($this->table[$j][$i])>0){
$passed = true;
}
if($passed && !$counting && count($this->table[$j][$i])==0){
$counting = true;
}
else{
$counting = false;
}
if($passed && $counting){
$total++;
}
}
}
return $total;
}
Your help is appreciated.
I have an answer in javascript, try this:
var arr = [[1,2,3,null,5],[1,2,3,null,5],[null,2,null,null,5],[null,2,3,4,null],[1,null,null,4,5],[1,2,3,4,null]];
var hole = 0;
for(var i=0; i<arr.length; i++){
for(var j=1; j<arr[i].length-1; j++){
if(arr[i][j]==null){
for(var k=j;k<arr[i].length; k++){
if(arr[i][k] != null){
k = arr[i].length;
}else{
j++;
}
}
if(j < arr[i].length){
hole++;
}
}
}
}
alert(hole);
'hole' is the var with the number of holes
So if I understand correctly, you just want to know how many empty cells you have in your array which isn't on an edge.
Similar to counting the number of spaces in a sentence, but not counting the whitespace at the beginning or end?
public function countHoles()
{
$total = 0;
// Start at 1 and go to Count() - 2
for($i = 0; $i < 5; $i++) // Horizontal
for($j = 1; $j < 9; $j++) // Vertical
{
if (j == 1) // 2nd row
{
if ($this->table[$i][$j] == null && $this->table[$i][0] != null)
$total++;
}
else if (j == 3) // 2nd last row
{
if ($this->table[$i][$j] == null && $this->table[$i][4] != null)
$total++;
}
else
{
if ($this->table[$i][$j] == null)
$total++;
}
}
return $total;
}
Is this what you mean?
(You may need to replace the == null and != null with whatever other 'emptyness' check you need. Also, the nested IFs can obviously be condensed - I wrote them expanded for ease of understanding.)
Related
This code is working fine when the array length is 8 or 10 only. When we are checking this same code for more than 10 array length.it get loading not showing the results.
How do reduce my code. If you have algorithm please share. Please help me.
This program working flow:
$allowed_per_room_accommodation =[2,3,6,5,3,5,2,5,4];
$allowed_per_room_price =[10,30,60,40,30,50,20,60,80];
$search_accommodation = 10;
i am get subsets = [5,5],[5,3,2],[6,4],[6,2,2],[5,2,3],[3,2,5]
Show lowest price room and then equal of 10 accommodation; output like as [5,3,2];
<?php
$dp=array(array());
$GLOBALS['final']=[];
$GLOBALS['room_key']=[];
function display($v,$room_key)
{
$GLOBALS['final'][] = $v;
$GLOBALS['room_key'][] = $room_key;
}
function printSubsetsRec($arr, $i, $sum, $p,$dp,$room_key='')
{
// If we reached end and sum is non-zero. We print
// p[] only if arr[0] is equal to sun OR dp[0][sum]
// is true.
if ($i == 0 && $sum != 0 && $dp[0][$sum]) {
array_push($p,$arr[$i]);
array_push($room_key,$i);
display($p,$room_key);
return $p;
}
// If $sum becomes 0
if ($i == 0 && $sum == 0) {
display($p,$room_key);
return $p;
}
// If given sum can be achieved after ignoring
// current element.
if (isset($dp[$i-1][$sum])) {
// Create a new vector to store path
// if(!is_array(#$b))
// $b = array();
$b = $p;
printSubsetsRec($arr, $i-1, $sum, $b,$dp,$room_key);
}
// If given $sum can be achieved after considering
// current element.
if ($sum >= $arr[$i] && isset($dp[$i-1][$sum-$arr[$i]]))
{
if(!is_array($p))
$p = array();
if(!is_array($room_key))
$room_key = array();
array_push($p,$arr[$i]);
array_push($room_key,$i);
printSubsetsRec($arr, $i-1, $sum-$arr[$i], $p,$dp,$room_key);
}
}
// Prints all subsets of arr[0..n-1] with sum 0.
function printAllSubsets($arr, $n, $sum,$get=[])
{
if ($n == 0 || $sum < 0)
return;
// Sum 0 can always be achieved with 0 elements
// $dp = new bool*[$n];
$dp = array();
for ($i=0; $i<$n; ++$i)
{
// $dp[$i][$sum + 1]=true;
$dp[$i][0] = true;
}
// Sum arr[0] can be achieved with single element
if ($arr[0] <= $sum)
$dp[0][$arr[0]] = true;
// Fill rest of the entries in dp[][]
for ($i = 1; $i < $n; ++$i) {
for ($j = 0; $j < $sum + 1; ++$j) {
// echo $i.'d'.$j.'.ds';
$dp[$i][$j] = ($arr[$i] <= $j) ? (isset($dp[$i-1][$j])?$dp[$i-1][$j]:false) | (isset($dp[$i-1][$j-$arr[$i]])?($dp[$i-1][$j-$arr[$i]]):false) : (isset($dp[$i - 1][$j])?($dp[$i - 1][$j]):false);
}
}
if (isset($dp[$n-1][$sum]) == false) {
return "There are no subsets with";
}
$p;
printSubsetsRec($arr, $n-1, $sum, $p='',$dp);
}
$blockSize = array('2','3','6','5','3','5','2','5','4');
$blockvalue = array('10','30','60','40','30','50','20','60','80');
$blockname = array("map","compass","water","sandwich","glucose","tin","banana","apple","cheese");
$processSize = 10;
$m = count($blockSize);
$n = count($processSize);
// sum of sets in array
printAllSubsets($blockSize, $m, $processSize);
$final_subset_room = '';
$final_set_room_keys = '';
$final_set_room =[];
if($GLOBALS['room_key']){
foreach ($GLOBALS['room_key'] as $set_rooms_key => $set_rooms) {
$tot = 0;
foreach ($set_rooms as $set_rooms) {
$tot += $blockvalue[$set_rooms];
}
$final_set_room[$set_rooms_key] = $tot;
}
asort($final_set_room);
$final_set_room_first_key = key($final_set_room);
$final_all_room['set_room_keys'] = $GLOBALS['room_key'][$final_set_room_first_key];
$final_all_room_price['set_room_price'] = $final_set_room[$final_set_room_first_key];
}
if(isset($final_all_room_price)){
asort($final_all_room_price);
$final_all_room_first_key = key($final_all_room_price);
foreach ($final_all_room['set_room_keys'] as $key_room) {
echo $blockname[$key_room].'---'. $blockvalue[$key_room];
echo '<br>';
}
}
else
echo 'No Results';
?>
I'm assuming your task is, given a list rooms, each with the amount of people it can accommodate and the price, to accommodate 10 people (or any other quantity).
This problem is similar to 0-1 knapsack problem which is solvable in polynomial time. In knapsack problem one aims to maximize the price, here we aim to minimize it. Another thing that is different from classic knapsack problem is that full room cost is charged even if the room is not completely occupied. It may reduce the effectiveness of the algorithm proposed at Wikipedia. Anyway, the implementation isn't going to be straightforward if you have never worked with dynamic programming before.
If you want to know more, CLRS book on algorithms discusses dynamic programming in Chapter 15, and knapsack problem in Chapter 16. In the latter chapter they also prove that 0-1 knapsack problem doesn't have trivial greedy solution.
The German Tax Id (Steueridentifikationsnummer) has the following properties:
It has 11 digits
First digit cannot be 0
In the first ten digits: one number occurs exactly twice or thrice, one or two digits appear zero times and the other digits appear exactly once
The last digit is a checksum Example Code for Checksum
The third bulletpoint is a little difficult for me to solve in an elegant way. I already have the code for the other three bulletpoints, but would love to get input for the last one, so that this could be a small little reference for other people.
# validate tax number
$taxNumber = $_POST['taxNumber'];
echo preg_replace("/[^0-9]/", "", $taxNumber);
if (strlen($taxNumber != 11)) {
# 11 digits
$taxNumberValid = false;
} else if ($taxNumber[0] == "0") {
# first digit != 0
$taxNumberValid = false;
} else {
# one digit two times, one digit zero times
# checksum
$numbers = str_split($taxNumber);
$sum = 0;
$product = 10;
for ($i = 0; $i <= 9; $i++) {
$sum = ($numbers[$i] + $product) % 10;
if ($sum == 0) {
$sum = 10;
}
$product = ($sum * 2) % 11;
}
$checksum = 11 - $product;
if ($checksum == 10) {
$checksum = 0;
}
if ($taxNumber[10] != $checksum) {
$taxNumberValid = false;
}
}
This code solves the problem:
// remove whitespaces, slashes & other unnecessary characters
$taxNumber = preg_replace("/[^0-9]/", "", $taxNumber);
// by default the taxnumber is correct
$taxNumberValid = true;
// taxnumber has to have exactly 11 digits
if (strlen($taxNumber) != 11) {
$taxNumberValid = false;
}
// first digit cannot be 0
if ($taxNumber[0] == "0") {
$taxNumberValid = false;
}
/*
make sure that within the first ten digits:
1.) one digit appears exactly twice or thrice
2.) one or two digits appear zero times
3.) and oll other digits appear exactly once once
*/
$digits = str_split($taxNumber);
$first10Digits = $digits;
array_pop($first10Digits);
$countDigits = array_count_values ($first10Digits);
if (count($countDigits) != 9 && count($countDigits) != 8) {
$taxNumberValid = false;
}
// last check: 11th digit has to be the correct checkums
// see http://de.wikipedia.org/wiki/Steueridentifikationsnummer#Aufbau_der_Identifikationsnummer
$sum = 0;
$product = 10;
for($i = 0; $i <= 9; $i++) {
$sum = ($digits[$i] + $product) % 10;
if ($sum == 0) {
$sum = 10;
}
$product = ($sum * 2) % 11;
}
$checksum = 11 - $product;
if ($checksum == 10) {
$checksum = 0;
}
if ($taxNumber[10] != $checksum) {
$taxNumberValid = false;
}
Update in 2017
Until 2016, the rule was, that within the first ten digits one number had to appear exactly twice.
Starting at 2017, the rule is, that within the first ten digits one number has to appear exactly twice or thrice.
And here is how you would write it in JS, based on #Pascal Klein's answer:
function countValues(arr) {
return arr.reduce((obj, item) => {
obj[item] = obj[item] ? ++obj[item] : 1;
return obj;
}, {});
}
function validateTIN(tin) {
const tinLength = 11;
// Taxnumber has to have exactly 11 digits.
if (tin.length !== tinLength) {
return false;
}
// First digit cannot be 0.
if (tin[0] === '0') {
return false;
}
/*
make sure that within the first ten digits:
1.) one digit appears exactly twice or thrice
2.) one or two digits appear zero times
3.) and all other digits appear exactly once
*/
const tinArray = tin.split('').slice(0, -1);
const valueCount = countValues(tinArray);
const valueCountLength = Object.keys(valueCount).length;
if (valueCountLength !== 8 && valueCountLength !== 9) {
return false;
}
// 11th digit has to match the checkum.
let sum = 0;
let product = 10;
for(let i = 0; i < tinLength - 1; i++) {
sum = (+tinArray[i] + product) % 10;
if (sum === 0) {
sum = 10;
}
product = (sum * 2) % 11;
}
let checksum = 11 - product;
if (checksum === 10) {
checksum = 0;
}
if (+tin[tinLength - 1] !== checksum) {
return false;
}
return true;
}
const tin1 = 'gbg';
const tin2 = '42344677908';
const tin3 = '12005078909';
const tin4 = '36574261809'; // valid
const tin5 = '10863924976'; // valid
console.log(tin1, validateTIN(tin1));
console.log(tin2, validateTIN(tin2));
console.log(tin3, validateTIN(tin3));
console.log(tin4, validateTIN(tin4));
console.log(tin5, validateTIN(tin5));
Here's a solution (in Javascript) that takes all the rules in consideration.
function validateTin(tin) {
// Allow space and slash (/) as number separators
tin = tin.replace(/ |\//g, "");
// 11 digits, the first is not allowed to be 0
if (!/^[1-9][0-9]{10}$/.test(tin)) {
return false;
}
const firstTen = tin.slice(0, 10);
// Count the number of occurrences of each digit
const occurrences = firstTen
.split("")
.reduce((acc, d) => acc.set(d, (acc.get(d) || 0) + 1), new Map());
const keys = [...occurrences.keys()];
const values = [...occurrences.values()];
// If one digit occurs twice, the length of keys will be 9
// If one digit occurs three times OR if two different digits occurs twice
// each, the length will be 8
if (keys.length !== 9 && keys.length !== 8) {
return false;
}
if (keys.length === 8) {
// Check how many times the digit that occurred the most times occurred
const maxOccurrences = values.reduce((max, num) => Math.max(max, num));
// If maxOccurrences is 2, we know two different numbers occurred twice
// each. This is not a valid tin.
// A final restriction is that a number can not occur three times in a row
if (maxOccurrences === 2 || /(\d)\1\1/.test(firstTen)) {
return false;
}
}
// Calculate the checksum digit
let m11 = 10;
let m10 = 0;
for (let i = 0; i < 10; i++) {
m10 = (parseInt(tin[i], 10) + m11) % 10;
if (m10 === 0) {
m10 = 10;
}
m11 = (2 * m10) % 11;
}
let digit = 11 - m11;
if (digit === 10) {
digit = 0;
}
return digit === parseInt(tin[10], 10);
}
I am making an ajax call in jquery
$.get("validate_isbn.php", {isbn: obj[16]},
function(answer)
{
console.log(answer);
if (answer == "valid")
{
var checked1 = $(elements[index]).val();
//$(elements[index]).val().append("<img src = 'pics/green_checkmark.png'>"); //doesn't work
//elements.after("<img src = 'pics/green_checkmark.png'>"); //sets all the elements with this pic
elements.eq(index).after("<img src='pics/green_checkmark.png' id='checkmark'>");
var checked = $(elements[index]).val();
}
});
which worked fine. I saw in the debugger that it was properly sending over the variable isbn with a isbn number from the obj array. My problem is on the php side. When I was testing, I simply had the code echo "valid" and everything worked out fine. But now when I put the real code in it stopped working:
<?php
//This algorithm is for ISBN 10
function is_isbn_10_valid($n){
$check = 0;
for ($i = 0; $i < 9; $i++)
{
$check += (10 - $i) * substr($n, $i, 1); //starting at the leftmost digit, multiple each digit by a constant, starting at 10, add the total
}
$t = substr($n, 9, 1); // tenth digit (aka checksum or check digit)
$check += ($t == 'x' || $t == 'X') ? 10 : $t; //now add the tenth digit
return $check % 11 == 0;
}
//The algorithm for ISBN 13 validation is as follows:
//Multiply each digit of teh isbn, starting at the left, with 1,3,3... etc for the entire isbn (including the check digit becuase its
//just going to be multiplied by 1 anyways.
//Add them all together, do mod 10 and voila!
function is_isbn_13_valid($n){
$check = 0;
for ($i = 0; $i < 13; $i+=2) //this does digits 1,3,5,7,9,10,11,13
{
$check += substr($n, $i, 1);
}
for ($i = 1; $i < 12; $i+=2) //this does digits 2,4,6,8,10,12
{
$check += 3 * substr($n, $i, 1);
}
return $check % 10 == 0;
}
$isbn = $_GET["isbn"];
if (strlen($isbn) = 10)
{
$result = is_isbn_10_valid($isbn);
}
else if (strlen($isbn) = 13)
{
$result = is_isbn_13_valid($isbn);
}
else
{
$result false;
}
if ($result === true)
{echo "valid";}
else if ($result === false)
{echo "not valid";}
?>
(Note: I'm sure that I can be more efficient and just return the boolean, but I refrained from that at the moment since I wasn't sure how the jquery .get would take it, as a boolean or text...)
Anyways, it doesn't work. The error on the console.log gives me:
Fatal error: Can't use function return value in write context in ...pathname here...\validate_isbn.php on line 31
On line 31, you have this:
if ($strlen($isbn) = 10)
Remove the $ on the strlen function, and change the = (assignment operator) to a == (equivalence operator). It should now look like this:
if (strlen($isbn) == 10)
You'll need to do the same a few lines after that, too.
Edit: One more thing. About five lines from the bottom, you're missing an equal sign.
$result false;
Should be:
$result = false;
Does anybody know a PHP function for IMEI validation?
Short solution
You can use this (witchcraft!) solution, and simply check the string length:
function is_luhn($n) {
$str = '';
foreach (str_split(strrev((string) $n)) as $i => $d) {
$str .= $i %2 !== 0 ? $d * 2 : $d;
}
return array_sum(str_split($str)) % 10 === 0;
}
function is_imei($n){
return is_luhn($n) && strlen($n) == 15;
}
Detailed solution
Here's my original function that explains each step:
function is_imei($imei){
// Should be 15 digits
if(strlen($imei) != 15 || !ctype_digit($imei))
return false;
// Get digits
$digits = str_split($imei);
// Remove last digit, and store it
$imei_last = array_pop($digits);
// Create log
$log = array();
// Loop through digits
foreach($digits as $key => $n){
// If key is odd, then count is even
if($key & 1){
// Get double digits
$double = str_split($n * 2);
// Sum double digits
$n = array_sum($double);
}
// Append log
$log[] = $n;
}
// Sum log & multiply by 9
$sum = array_sum($log) * 9;
// Compare the last digit with $imei_last
return substr($sum, -1) == $imei_last;
}
Maybe can help you :
This IMEI number is something like this: ABCDEF-GH-IJKLMNO-X (without “-” characters)
For example: 350077523237513
In our example ABCDEF-GH-IJKLMNO-X:
AB is Reporting Body Identifier such as 35 = “British Approvals Board of Telecommunications (BABT)”
ABCDEF is Type Approval Code
GH is Final Assembly Code
IJKLMNO is Serial Number
X is Check Digit
Also this can help you : http://en.wikipedia.org/wiki/IMEI#Check_digit_computation
If i don't misunderstood, IMEI numbers using Luhn algorithm . So you can google this :) Or you can search IMEI algorithm
Maybe your good with the imei validator in the comments here:
http://www.php.net/manual/en/function.ctype-digit.php#77718
But I haven't tested it
Check this solution
<?php
function validate_imei($imei)
{
if (!preg_match('/^[0-9]{15}$/', $imei)) return false;
$sum = 0;
for ($i = 0; $i < 14; $i++)
{
$num = $imei[$i];
if (($i % 2) != 0)
{
$num = $imei[$i] * 2;
if ($num > 9)
{
$num = (string) $num;
$num = $num[0] + $num[1];
}
}
$sum += $num;
}
if ((($sum + $imei[14]) % 10) != 0) return false;
return true;
}
$imei = '868932036356090';
var_dump(validate_imei($imei));
?>
IMEI validation uses Luhn check algorithm. I found a link to a page where you can validate your IMEI. Furthermore, at the bottom of this page is a piece of code written in JavaScript to show how to calculate the 15th digit of IMEI and to valid IMEI. I might give you some ideas. You can check it out here http://imei.sms.eu.sk/index.html
Here is a jQuery solution which may be of use: https://github.com/madeinstefano/imei-validator
good fun from kasperhartwich
function validateImei($imei, $use_checksum = true) {
if (is_string($imei)) {
if (ereg('^[0-9]{15}$', $imei)) {
if (!$use_checksum) return true;
for ($i = 0, $sum = 0; $i < 14; $i++) {
$tmp = $imei[$i] * (($i%2) + 1 );
$sum += ($tmp%10) + intval($tmp/10);
}
return (((10 - ($sum%10)) %10) == $imei[14]);
}
}
return false;
}
[Disclaimer: I am new to PHP, and I am just learning, so please no flamers, it really hinders the learning process when one is trying to find solutions or information, thank you, and the code works fine in terms of the crossword puzzle, it's just really baffling me how one gets a diagonal orientation with the given information, or what I am doing wrong and not seeing?]
Given a switch:
switch ($dir){
case "E":
//col from 0 to board width - word width
//row from 0 to board height
$newCol = rand(0, $boardData["width"] - 1 - strlen($theWord));
$newRow = rand(0, $boardData["height"]-1);
for ($i = 0; $i < strlen($theWord); $i++){
//new character same row, initial column + $i
$boardLetter = $board[$newRow][$newCol + $i];
$wordLetter = substr($theWord, $i, 1);
//check for legal values in current space on board
if (($boardLetter == $wordLetter) ||
($boardLetter == ".")){
$board[$newRow][$newCol + $i] = $wordLetter;
} else {
$itWorked = FALSE;
} // end if
} // end for loop
break;
AND:
case "N":
//col from 0 to board width
//row from word length to board height
$newCol = rand(0, $boardData["width"] -1);
$newRow = rand(strlen($theWord), $boardData["height"]-1);
for ($i = 0; $i < strlen($theWord); $i++){
//check for a legal move
$boardLetter = $board[$newRow - $i][$newCol];
$wordLetter = substr($theWord, $i, 1);
if (($boardLetter == $wordLetter) ||
($boardLetter == ".")){
$board[$newRow - $i][$newCol] = $wordLetter;
} else {
$itWorked = FALSE;
} // end if
} // end for loop
break;
I should be able to combine the two to get NE (or diagonal text being outputted onto the screen)
HOWEVER, when I try this, it's not working, and I have been trying different combinations
of N and E to get NE or a diagonal NE orientation with no luck, what gives?
#Tried multiple different combination's of N & E, I am out of ideas
switch ($dir){
case "E":
$newCol = rand(0, $boardData["width"] - 1 - strlen($theWord));
$newRow = rand(strlen($theWord), $boardData["height"]-1);
for ($i = 0; $i < strlen($theWord); $i++){
#Combined but no luck, WTF:
$boardLetter = $board[$newRow][$newRow - $i];
$boardLetter = $board[$newCol][$newCol + $i];
$wordLetter = substr($theWord, $i, 1);
//check for legal values in current space on board
if (($boardLetter == $wordLetter) ||
($boardLetter == ".")){
$board[$newRow][$newRow - $i] = $wordLetter;
$board[$newCol][$newCol + $i] = $wordLetter;
} else {
$itWorked = FALSE;
} // end if
} // end for loop
break;
The break; statement will break out of the switch clause after running the code for case "E". You'll need to set up new, explicit cases for the combinations to make it work that way.