Check if array elements are undefined from an XSUB - perl

I am trying to check if an array element is undef from an XSUB like this:
void
print_array(array)
AV *array
PREINIT:
int len;
SV **sv_ptr;
SV *sv;
int i;
CODE:
len = av_len(array) + 1;
printf("[");
for (i = 0; i < len; i++) {
sv_ptr = av_fetch( array, i, 0 );
if (!sv_ptr) {
printf("empty");
}
else {
sv = *sv_ptr;
if (sv == &PL_sv_undef) {
printf("undef");
}
else {
printf("*");
}
}
if (i < (len - 1)) {
printf(", ");
}
}
printf("]\n");
If I run this sub from a Perl script:
use strict;
use warnings;
use ArrayPrint;
my $array = [];
$array->[4] = undef;
ArrayPrint::print_array($array);
The output is:
[empty, empty, empty, empty, *]
Why is the last element not showing undef?

An SV can hold an undefined value but still be a different SV than PL_sv_undef. You need to replace the PL_sv_undef test with
SvGETMAGIC(sv);
if (!SvOK(sv)) { printf "undef" } else { printf "*" }

Related

In Flutter and if the number after decimal point is equal 0 convert the number to int

This is a function if the endValueFixed is equal for example 12.0 I want to print the number without zero so I want it to be 12.
void calculateIncrease() {
setState(() {
primerResult = (startingValue * percentage) / 100;
endValue = startingValue + primerResult;
endValueFixe`enter code here`d = roundDouble(endValue, 2);
});
}
This may be an overkill but it works exactly as you wish:
void main() {
// This is your double value
final end = 98.04;
String intPart = "";
String doublePart = "";
int j = 0;
for (int i = 0; i < end.toString().length; i++) {
if (end.toString()[i] != '.') {
intPart += end.toString()[i];
} else {
j = i + 1;
break;
}
}
for (int l = j; l < end.toString().length; l++) {
doublePart += end.toString()[l];
}
if (doublePart[0] == "0" && doublePart[1] != "0") {
print(end);
} else {
print(end.toString());
}
}
You may use this code as a function and send whatever value to end.
if (endValueFixed==12) {
print('${endValueFixed.toInt()}');
}
conditionally cast it to an int and print it then :)

How can I speed up this nested foreach loop in Perl?

I have a Perl script that compares two sets of data loaded into two arrays, and I'm trying to make the comparison more efficient. Currently the code is as follows:
foreach(#{FILE_DATA}) {
if((++$file_current_linenum % 200) == 0) {
$progress = int($file_current_linenum / $file_total_lines * 10000) / 100;
logg("Processed $file_current_linenum file rows, $progress%, $mismatches mismatches.");
}
$file_current_line = $_;
$match_found = 0;
foreach(#{DB_DATA}) {
$db_current_line = $_;
if($file_current_line->{"channel"} == $db_current_line->{"channel"} ) {
if ($file_current_line->{"checksum"} == $db_current_line->{"checksum"} &&
$file_current_line->{"time"} > ($db_current_line->{"date_part"} - $TIME_MATCH_TOLERANCE) &&
$file_current_line->{"time"} < ($db_current_line->{"date_part"} + $TIME_MATCH_TOLERANCE) ){
$match_found = 1;
last; # break;
}
}
}
if($match_found != 1) {
push(#results, $file_current_line);
$mismatches++;
}
}
My first thought would be to remove matches from both arrays to reduce the pool size, would that affect the iterators position?
Both sets of data can have up to a couple of million elements and the comparison can take a few hours to complete.
Your solution is O(DB * FILE).
The following is O(DB + FILE) if and only if there never more than a few lines with the same channel and checksum:
my %DB_DATA;
for my $db_line (#DB_DATA) {
push #{ $DB_DATA{ $db_line->{channel} }{ $db_line->{checksum} } }, $db_line;
}
for my $file_line_idx (0..$#FILE_DATA) {
my $file_line = $FILE_DATA[$file_line_idx];
my $found = 0;
if (my $r1 = $DB_DATA{ $file_line->{channel} } ) {
if (my $r2 = $r1->{ $file_line->{checksum} } ) {
my $file_time = $file_line->{time};
for my $db_line (#$r2) {
my $db_time = $db_line->{date_part};
if (abs($file_time - $db_time) < $TIME_MATCH_TOLERANCE) {
$found = 1;
last;
}
}
}
}
push #mismatches, $file_line if !$found;
if ((($file_line_idx+1) % 200) == 0) {
logg(sprintf("Processed %d file rows, %d%, %d mismatches.",
$file_line_idx+1,
int(($file_line_idx+1)/#FILE_DATA) * 100,
0+#mismatches,
));
}
}
The following is O(DB + FILE) even if there are many lines with the same channel and checksum, but uses a lot of memory if $TIME_MATCH_TOLERANCE is big:
my %DB_DATA;
for my $db_line (#DB_DATA) {
for my $db_time (
$db_line->{date_part} - $TIME_MATCH_TOLERANCE + 1
..
$db_line->{date_part} + $TIME_MATCH_TOLERANCE - 1
) {
++$DB_DATA{ $db_line->{channel} }{ $db_line->{checksum} }{$db_time};
}
}
for my $file_line_idx (0..$#FILE_DATA) {
my $file_line = $FILE_DATA[$file_line_idx];
my $found = 0;
if (my $r1 = $DB_DATA{ $file_line->{channel} } ) {
if (my $r2 = $r1->{ $file_line->{checksum} } ) {
if ($r2->{ $file_line->{time} } {
$found = 1;
last;
}
}
}
push #mismatches, $file_line if !$found;
if ((($file_line_idx+1) % 200) == 0) {
logg(sprintf("Processed %d file rows, %d%, %d mismatches.",
$file_line_idx+1,
int(($file_line_idx+1)/#FILE_DATA) * 100,
0+#mismatches,
));
}
}
Note: Assumes the timestamps are integers. If they're not, convert them to integers before using them as keys.
The following is O((DB + FILE) log DB) [ which is very close to O(DB + FILE) ] even if there are many lines with the same channel and checksum, and uses minimal memory:
sub binsearch(&\#) {
my ($compare, $array) = #_;
my $i = 0;
my $j = $#$array;
return 0 if $j == -1;
while (1) {
my $k = int(($i+$j)/2);
for ($array->[$k]) {
my $cmp = $compare->()
or return 1;
if ($cmp < 0) {
$j = $k-1;
return 0 if $i > $j;
} else {
$i = $k+1;
return 0 if $i > $j;
}
}
}
}
my %DB_DATA;
for my $db_line (#DB_DATA) {
push #{ $DB_DATA{ $db_line->{channel} }{ $db_line->{checksum} } }, $db_line;
}
for my $r1 (values(%DB_DATA)) {
for my $r2 (values(%$r1)) {
#$r2 = sort { $a->{date_part} <=> $b->{date_part} } #$r2;
}
}
for my $file_line_idx (0..$#FILE_DATA) {
my $file_line = $FILE_DATA[$file_line_idx];
my $found = 0;
if (my $r1 = $DB_DATA{ $file_line->{channel} } ) {
if (my $r2 = $r1->{ $file_line->{checksum} } ) {
my $file_time = $file_line->{time};
my $min_db_time = $file_time - $TIME_MATCH_TOLERANCE;
my $max_db_time = $file_time + $TIME_MATCH_TOLERANCE;
if ( binsearch {
$_->{date_part} >= $max_db_time ? -1
: $_->{date_part} <= $min_db_time ? +1
: 0
} #$r2 ) {
$found = 1;
last;
}
}
}
push #mismatches, $file_line if !$found;
if ((($file_line_idx+1) % 200) == 0) {
logg(sprintf("Processed %d file rows, %d%, %d mismatches.",
$file_line_idx+1,
int(($file_line_idx+1)/#FILE_DATA) * 100,
0+#mismatches,
));
}
}
You could probably reduce the time significantly by pre-building a hash from DB_DATA, using the concatenation of the "channel" and "checksum" values as the key, and each value being a list of all of the DB_DATA entries with that channel and checksum. That way, for each FILE_DATA entry, you only need to check that list.
If there are a lot of entries with a given channel and checksum, you try to improve even more by sorting them by date_part, and then trying to binary search to find a valid entry.
If there are very few entries with a given channel and checksum, this should reduce your run time by a factor of a million or so, since it reduces the run time from O($#FILE_DATA * $#DB_DATA) to O($#FILE_DATA + $#DB_DATA).

least recently used algorithm in C for operating system

I made this code, however this shows a different value for page faults. Please help me.
time is an array which will store the number of times a page is referenced. And "foo" is a function designed to return the minimum time one page in the frame list.
#include <stdio.h>
int p,i,b,a[50],f[30],counter,fault;
int time[10] = {0};
int foo (void);
int main (void)
{
int min,flag,j;
printf("Enter the number of frames\n");
scanf("%d",&b);
for ( i = 0; i < b; i++ )
f[i] = -1;
printf("Enter the number of pages\n");
scanf("%d",&p);
printf("Enter the pages\n");
for ( i = 0; i < p; i++ )
scanf("%d",&a[i]);
fault = 0, counter = 0;
for (i = 0; i < p; i++)
{
flag = 0;
if ( i < b )
{
f[i] = a[i];
fault++;
time[i]++;
}
else
{
for ( j = 0; j < b; j++ )
{
if ( a[i] == f[j] )
{
flag = 1;
time[j]++;
}
}
if ( flag == 0 )
{
min = foo();
printf("The page replaced for %d page is at pos %d\n",i,min);
f[min] = a[i];
fault++;
time[min]++;
}
}
}
printf("The number of page faults are %d\n",fault);
return 0;
}
int foo (void)
{
int z,bar1, bar2;
bar1 = time[0];
bar2 = 0;
for ( z = 1; z < b; z++ )
{
if ( time[z] < bar1 )
{
bar1 = time[z];
bar2 = z;
}
}
return bar2;
}

How to determine if a string can be manipulated to be rewritten as a palindrome?

I believe this can be achieved by counting the instances for each character in that string. Even if a single character in that string is repeated at least twice, we can declare that string as a palindrome.
For example: bbcccc can be rewritten as bccccb or ccbbcc.
edified can be rewritten as deified.
Some book mentioned we should be using hash table. I think we can just use a list and check for the character count.
Do you think the logic is correct?
Yes, the main idea is to count the times of each char existing in the string. And it will be true if the string has at most one char occurs odd times and all others even times.
For example:
aabbcc => acbbca
aabcc => acbca
aabbb => abbba
No. You don't have to use a hash map (as some of the other answers suggest). But the efficiency of the solution will be determined by the algorithm you use.
Here is a solution that only tracks odd characters. If we get 2 odds, we know it can't be a scrambled palindrome. I use an array to track the odd count. I reuse the array index 0 over and over until I find an odd. Then I use array index 1. If I find 2 odds, return false!
Solution without a hash map in javascript:
function isScrambledPalindrome(input) {
// TODO: Add error handling code.
var a = input.split("").sort();
var char, nextChar = "";
var charCount = [ 0 ];
var charIdx = 0;
for ( var i = 0; i < a.length; ++i) {
char = a[i];
nextChar = a[i + 1] || "";
charCount[charIdx]++;
if (char !== nextChar) {
if (charCount[charIdx] % 2 === 1) {
if (charCount.length > 1) {
// A scrambled palindrome can only have 1 odd char count.
return false;
}
charIdx = 1;
charCount.push(0);
} else if (charCount[charIdx] % 2 === 0) {
charCount[charIdx] = 0;
}
}
}
return true;
}
console.log("abc: " + isScrambledPalindrome("abc")); // false
console.log("aabbcd: " + isScrambledPalindrome("aabbcd")); // false
console.log("aabbb: " + isScrambledPalindrome("aabbb")); // true
console.log("a: " + isScrambledPalindrome("a")); // true
Using a hash map, I found a cool way to only track the odd character counts and still determine the answer.
Fun javascript hash map solution:
function isScrambledPalindrome( input ) {
var chars = {};
input.split("").forEach(function(char) {
if (chars[char]) {
delete chars[char]
} else {
chars[char] = "odd" }
});
return (Object.keys(chars).length <= 1);
}
isScrambledPalindrome("aba"); // true
isScrambledPalindrome("abba"); // true
isScrambledPalindrome("abca"); // false
Any string can be palindrome only if at most one character occur odd no. of times and all other characters must occur even number of times.
The following program can be used to check whether a palindrome can be string or not.
vector<int> vec(256,0); //Vector for all ASCII characters present.
for(int i=0;i<s.length();++i)
{
vec[s[i]-'a']++;
}
int odd_count=0,flag=0;
for(int i=0;i<vec.size();++i)
{
if(vec[i]%2!=0)
odd_count++;
if(odd_count>1)
{
flag=1;
cout<<"Can't be palindrome"<<endl;
break;
}
}
if(flag==0)
cout<<"Yes can be palindrome"<<endl;
My code check if can it is palindrome or can be manipulated to Palindrome
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
//Tested on windows 64 bit arhc by using cygwin64 and GCC
bool isPalindrome (char *text);
int main()
{
char text[100]; // it could be N with defining N
bool isPal,isPosPal = false;
printf("Give me a string to test if it is Anagram of Palindrome\n");
gets(text);
isPal = isPalindrome(text);
isPosPal = isAnagramOfPalindrome(text);
if(isPal == false)
{
printf("Not a palindrome.\n");
}
else
{
printf("Palindrome.\n");
}
if(isPosPal == false)
{
printf("Not Anagram of Palindrome\n");
}
else
{
printf("Anagram of Palindrome\n");
}
return 0;
}
bool isPalindrome (char *text) {
int begin, middle, end, length = 0;
length = getLength(text);
end = length - 1;
middle = length/2;
for (begin = 0; begin < middle; begin++)
{
if (text[begin] != text[end])
{
return false;
}
end--;
}
if (begin == middle)
return true;
}
int getLength (char *text) {
int length = 0;
while (text[length] != '\0')
length++;
printf("length: %d\n",length);
return length;
}
int isAnagramOfPalindrome (char *text) {
int length = getLength(text);
int i = 0,j=0;
bool arr[26] = {false};
int counter = 0;
//char string[100]="neveroddoreven";
int a;
for (i = 0; i < length; i++)
{
a = text[i];
a = a-97;
if(arr[a])
{
arr[a] = false;
}
else
{
arr[a] = true;
}
}
for(j = 0; j < 27 ; j++)
{
if (arr[a] == true)
{
counter++;
}
}
printf("counter: %d\n",counter);
if(counter > 1)
{
return false;
}
else if(counter == 1)
{
if(length % 2 == 0)
return false;
else
return true;
}
else if(counter == 0)
{
return true;
}
}
as others have posted, the idea is to have each character occur an even number of times for an even length string, and one character an odd number of times for an odd length string.
The reason the books suggest using a hash table is due to execution time. It is an O(1) operation to insert into / retrieve from a hash map. Yes a list can be used but the execution time will be slightly slower as the sorting of the list will be O(N log N) time.
Pseudo code for a list implementation would be:
sortedList = unsortedList.sort;
bool oddCharFound = false;
//if language does not permit nullable char then initialise
//current char to first element, initialise count to 1 and loop from i=1
currentChar = null;
currentCharCount = 0;
for (int i=0; i <= sortedList.Length; i++) //start from first element go one past end of list
{
if(i == sortedList.Length
|| sortedList[i] != currentChar)
{
if(currentCharCount % 2 = 1)
{
//check if breaks rule
if((sortedList.Length % 2 = 1 && oddCharFound)
|| oddCharFound)
{
return false;
}
else
{
oddCharFound = true;
}
}
if(i!= sortedList.Length)
{
currentCharCount = 1;
currentChar = sortedList[i];
}
}
else
{
currentCharCount++;
}
}
return true;
Here is a simple solution using an array; no sort needed
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[256] = { 0 };
unsigned char i[] = {"aaBcBccc"};
unsigned char *p = &i[0];
int c = 0;
int j;
int flag = 0;
while (*p != 0)
{
a[*p]++;
p++;
}
for(j=0; j<256; j++)
{
if(a[j] & 1)
{
c++;
if(c > 1)
{
flag = 1;
break;
}
}
}
if(flag)
printf("Nope\n");
else
printf("yup\n");
return 0;
}
C#:
bool ok = s.GroupBy(c => c).Select(g => g.Count()).Where(c => c == 1).Count() < 2;
This solution, however, does use hashing.
Assuming all input characters are lower case letters.
#include<stdio.h>
int main(){
char *str;
char arr[27];
int j;
int a;
j = 0;
printf("Enter the string : ");
scanf("%s", str);
while (*str != '\0'){
a = *str;
a = a%27;
if(arr[a] == *str){
arr[a]=0;
j--;
}else{
arr[a] = *str;
j++;
}
*str++;
}
if(j==0 || j== -1 || j==1){
printf ("\nThe string can be a palindrome\n");
}
}

fix rotate 3D object Perl code

I wrote this code using C++ example from net to rotate my set of points in 3D.
##matrix is points and their 3D coordinates.
#rotated_matrix = rotate_l(\#matrix, 0);
sub rotate_l {
my $ref = $_[0];
my $x = 0;
my $step = 1;
#if rotx
if ($_[1] == 0) {
while ($$ref[$x][0]) {
$$ref[$x][1] += ($$ref[$x][1]*cos($step) - $$ref[$x][2]*sin($step));
$$ref[$x][2] += ($$ref[$x][1]*sin($step) + $$ref[$x][2]*cos($step));
$x++;
}
}
#if roty
if ($_[1] == 1) {
while ($$ref[$x][0]) {
$$ref[$x][0] += ( $$ref[$x][0]*cos($step) + $$ref[$x][2]*sin($step));
$$ref[$x][2] += (-$$ref[$x][0]*sin($step) + $$ref[$x][2]*cos($step));
$x++;
}
}
#if rotz
if ($_[1] == 2) {
while ($$ref[$x][0]) {
$$ref[$x][0] += ($$ref[$x][0]*cos($step) - $$ref[$x][1]*sin($step));
$$ref[$x][1] += ($$ref[$x][0]*sin($step) + $$ref[$x][1]*cos($step));
$x++;
}
}
return #$ref;
}
But something is wrong. Object size/form fails to stay same. And my math is not that good to realize why. I even not sure I need += or =?
Thx amon. As suggested this works:
##matrix is points and their 3D coordinates.
#rotated_matrix = rotate_l(\#matrix, 0);
sub rotate_l {
my $ref = $_[0];
my $x = 0;
my $step = pi;
#if rotx
if ($_[1] == 0) {
while ($$ref[$x][0]) {
$$ref[$x][1] = ($$ref[$x][1]*cos($step) - $$ref[$x][2]*sin($step));
$$ref[$x][2] = ($$ref[$x][1]*sin($step) + $$ref[$x][2]*cos($step));
$x++;
}
}
#if roty
if ($_[1] == 1) {
while ($$ref[$x][0]) {
$$ref[$x][0] = ( $$ref[$x][0]*cos($step) + $$ref[$x][2]*sin($step));
$$ref[$x][2] = (-$$ref[$x][0]*sin($step) + $$ref[$x][2]*cos($step));
$x++;
}
}
#if rotz
if ($_[1] == 2) {
while ($$ref[$x][0]) {
$$ref[$x][0] = ($$ref[$x][0]*cos($step) - $$ref[$x][1]*sin($step));
$$ref[$x][1] = ($$ref[$x][0]*sin($step) + $$ref[$x][1]*cos($step));
$x++;
}
}
return #$ref;
}
If I need to rotate not around (0,0,0), but against other point the best way is to translate to 0 point rotate and then translate back?
Just as an example of what I meant by what I recommend you do:
#! /usr/bin/env perl
use common::sense;
use YAML 'Dump';
sub translate {
my ($deltaX, $deltaY) = #{pop()}; # <-- don't mind this.
for (#_) { # <--- this is the important part
$_->[0] += $deltaX;
$_->[1] += $deltaY;
}
#_
}
my #points = ([0, 1], [0, -1], [-1, 0], [1, 0]);
print Dump([translate #points, [2, 2]]);
my $box = \#points;
print Dump([translate #$box, [5, 0]]);