diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2023-03-27 00:36:00 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-27 00:36:00 +0100 |
| commit | 3d765a385b4345035433e6c361e6db4f1f07f75b (patch) | |
| tree | 1af11a7074a0716400ca48ae3082d545c9e911e8 | |
| parent | 711607e7c4455a272429fc62c97a8bafc4ca16a3 (diff) | |
| parent | 07744bc404fe0be15f6a50ab42d298df77464b81 (diff) | |
| download | perlweeklychallenge-club-3d765a385b4345035433e6c361e6db4f1f07f75b.tar.gz perlweeklychallenge-club-3d765a385b4345035433e6c361e6db4f1f07f75b.tar.bz2 perlweeklychallenge-club-3d765a385b4345035433e6c361e6db4f1f07f75b.zip | |
Merge pull request #7807 from dcw803/master
imported my solutions to this week's tasks, task 1 in Perl and C, task 2 in Perl…
| -rw-r--r-- | challenge-209/duncan-c-white/C/.cbuild | 1 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/Makefile | 19 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/README | 11 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/args.c | 207 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/args.h | 11 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/ch-1.c | 105 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/csvsplit.c | 47 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/csvsplit.h | 14 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/parseints.c | 114 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/parseints.h | 1 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/printarray.c | 39 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/C/printarray.h | 1 | ||||
| -rw-r--r-- | challenge-209/duncan-c-white/README | 103 | ||||
| -rwxr-xr-x | challenge-209/duncan-c-white/perl/ch-1.pl | 61 | ||||
| -rwxr-xr-x | challenge-209/duncan-c-white/perl/ch-2.pl | 114 |
15 files changed, 789 insertions, 59 deletions
diff --git a/challenge-209/duncan-c-white/C/.cbuild b/challenge-209/duncan-c-white/C/.cbuild index a14ec76520..835981f6f1 100644 --- a/challenge-209/duncan-c-white/C/.cbuild +++ b/challenge-209/duncan-c-white/C/.cbuild @@ -1,4 +1,5 @@ BUILD = ch-1 ch-2 +BUILD = ch-1 CFLAGS = -Wall -g #LDFLAGS = -lm #CFLAGS = -g diff --git a/challenge-209/duncan-c-white/C/Makefile b/challenge-209/duncan-c-white/C/Makefile new file mode 100644 index 0000000000..513f8703b6 --- /dev/null +++ b/challenge-209/duncan-c-white/C/Makefile @@ -0,0 +1,19 @@ +# Makefile rules generated by CB +CC = gcc +CFLAGS = -Wall -g +BUILD = ch-1 ch-2 + +all: $(BUILD) + +clean: + /bin/rm -f $(BUILD) *.o core a.out + +args.o: args.c +ch-1: ch-1.o args.o csvsplit.o +ch-1.o: ch-1.c args.h csvsplit.h +ch-2: ch-2.o args.o parseints.o printarray.o +ch-2.o: ch-2.c args.h parseints.h printarray.h +csvsplit.o: csvsplit.c csvsplit.h +parseints.o: parseints.c args.h parseints.h printarray.h +printarray.o: printarray.c + diff --git a/challenge-209/duncan-c-white/C/README b/challenge-209/duncan-c-white/C/README new file mode 100644 index 0000000000..dd5f3346f7 --- /dev/null +++ b/challenge-209/duncan-c-white/C/README @@ -0,0 +1,11 @@ +Thought I'd also have a go at translating ch-1.pl and ch-2.pl into C.. + +Both C versions produce identical (non-debugging and debugging) +output to the Perl originals. + +These C versions use most of my regular support modules: +- a command-line argument processing module args.[ch], +- a csvlist-of-int parsing module parseints.[ch], and +- an int-array printing module printarray.[ch]. +- plus a (new for PWC) csv splitting module csvsplit.[ch] to split + a single argument into a wordlist diff --git a/challenge-209/duncan-c-white/C/args.c b/challenge-209/duncan-c-white/C/args.c new file mode 100644 index 0000000000..d4a2d38b9a --- /dev/null +++ b/challenge-209/duncan-c-white/C/args.c @@ -0,0 +1,207 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + + +bool debug = false; + + +// process_flag_noarg( name, argc, argv ); +// Process the -d flag, and check that there are no +// remaining arguments. +void process_flag_noarg( char *name, int argc, char **argv ) +{ + int arg=1; + if( argc>1 && strcmp( argv[arg], "-d" ) == 0 ) + { + debug = true; + arg++; + } + + int left = argc-arg; + if( left != 0 ) + { + fprintf( stderr, "Usage: %s [-d]\n", name ); + exit(1); + } +} + + +// int argno = process_flag_n_args( name, argc, argv, n, argmsg ); +// Process the -d flag, and check that there are exactly +// n remaining arguments, return the index position of the first +// argument. If not, generate a fatal Usage error using the argmsg. +// +int process_flag_n_args( char *name, int argc, char **argv, int n, char *argmsg ) +{ + int arg=1; + if( argc>1 && strcmp( argv[arg], "-d" ) == 0 ) + { + debug = true; + arg++; + } + + int left = argc-arg; + if( left != n ) + { + fprintf( stderr, "Usage: %s [-d] %s\n Exactly %d " + "arguments needed\n", name, argmsg, n ); + exit(1); + } + return arg; +} + + +// int argno = process_flag_n_m_args( name, argc, argv, min, max, argmsg ); +// Process the -d flag, and check that there are between +// min and max remaining arguments, return the index position of the first +// argument. If not, generate a fatal Usage error using the argmsg. +// +int process_flag_n_m_args( char *name, int argc, char **argv, int min, int max, char *argmsg ) +{ + int arg=1; + if( argc>1 && strcmp( argv[arg], "-d" ) == 0 ) + { + debug = true; + arg++; + } + + int left = argc-arg; + if( left < min || left > max ) + { + fprintf( stderr, "Usage: %s [-d] %s\n Between %d and %d " + "arguments needed\n", name, argmsg, min, max ); + exit(1); + } + return arg; +} + + +// process_onenumarg_default( name, argc, argv, defvalue, &n ); +// Process the -d flag, and check that there is a single +// remaining numeric argument (or no arguments, in which case +// we use the defvalue), putting it into n +void process_onenumarg_default( char *name, int argc, char **argv, int defvalue, int *n ) +{ + char argmsg[100]; + sprintf( argmsg, "[int default %d]", defvalue ); + int arg = process_flag_n_m_args( name, argc, argv, 0, 1, argmsg ); + + *n = arg == argc ? defvalue : atoi( argv[arg] ); +} + + +// process_onenumarg( name, argc, argv, &n ); +// Process the -d flag, and check that there is a single +// remaining numeric argument, putting it into n +void process_onenumarg( char *name, int argc, char **argv, int *n ) +{ + int arg = process_flag_n_args( name, argc, argv, 1, "int" ); + + // argument is in argv[arg] + *n = atoi( argv[arg] ); +} + + +// process_twonumargs( name, argc, argv, &m, &n ); +// Process the -d flag, and check that there are 2 +// remaining numeric arguments, putting them into m and n +void process_twonumargs( char *name, int argc, char **argv, int *m, int *n ) +{ + int arg = process_flag_n_args( name, argc, argv, 2, "int" ); + + // arguments are in argv[arg] and argv[arg+1] + *m = atoi( argv[arg++] ); + *n = atoi( argv[arg] ); +} + + +// process_twostrargs() IS DEPRECATED: use process_flag_n_m_args() instead + + +// int arr[100]; +// int nel = process_listnumargs( name, argc, argv, arr, 100 ); +// Process the -d flag, and check that there are >= 2 +// remaining numeric arguments, putting them into arr[0..nel-1] +// and returning nel. +int process_listnumargs( char *name, int argc, char **argv, int *arr, int maxel ) +{ + int arg=1; + if( argc>1 && strcmp( argv[arg], "-d" ) == 0 ) + { + debug = true; + arg++; + } + + int left = argc-arg; + if( left < 2 ) + { + fprintf( stderr, "Usage: %s [-d] list_of_numeric_args\n", name ); + exit(1); + } + if( left > maxel ) + { + fprintf( stderr, "%s: more than %d args\n", name, maxel ); + exit(1); + } + + // elements are in argv[arg], argv[arg+1]... + + if( debug ) + { + printf( "debug: remaining arguments are in arg=%d, " + "firstn=%s, secondn=%s..\n", + arg, argv[arg], argv[arg+1] ); + } + + int nel = 0; + for( int i=arg; i<argc; i++ ) + { + arr[nel++] = atoi( argv[i] ); + } + arr[nel] = -1; + return nel; +} + + +// +// bool isint = check_unsigned_int( char *val, int *n ); +// Given an string val, check that there's an unsigned integer +// in it (after optional whitespace). If there is a valid +// unsigned integer value, store that integer value in *n and +// return true; otherwise return false (and don't alter *n). +bool check_unsigned_int( char *val, int *n ) +{ + // skip whitespace in val + char *p; + for( p=val; isspace(*p); p++ ) + { + /*EMPTY*/ + } + if( ! isdigit(*p) ) return false; + *n = atoi(p); + return true; +} + + +// +// bool ok = check_unsigned_real( char *val, double *n ); +// Given an string val, check that there's an unsigned real +// in it (after optional whitespace). If there is a valid +// unsigned real value, store that value in *n and +// return true; otherwise return false (and don't alter *n). +bool check_unsigned_real( char *val, double *n ) +{ + // skip whitespace in val + char *p; + for( p=val; isspace(*p); p++ ) + { + /*EMPTY*/ + } + if( ! isdigit(*p) ) return false; + *n = atof(p); + return true; +} diff --git a/challenge-209/duncan-c-white/C/args.h b/challenge-209/duncan-c-white/C/args.h new file mode 100644 index 0000000000..8844a8f9c4 --- /dev/null +++ b/challenge-209/duncan-c-white/C/args.h @@ -0,0 +1,11 @@ +extern bool debug; + +extern void process_flag_noarg( char * name, int argc, char ** argv ); +extern int process_flag_n_args( char * name, int argc, char ** argv, int n, char * argmsg ); +extern int process_flag_n_m_args( char * name, int argc, char ** argv, int min, int max, char * argmsg ); +extern void process_onenumarg_default( char * name, int argc, char ** argv, int defvalue, int * n ); +extern void process_onenumarg( char * name, int argc, char ** argv, int * n ); +extern void process_twonumargs( char * name, int argc, char ** argv, int * m, int * n ); +extern int process_listnumargs( char * name, int argc, char ** argv, int * arr, int maxel ); +extern bool check_unsigned_int( char * val, int * n ); +extern bool check_unsigned_real( char * val, double * n ); diff --git a/challenge-209/duncan-c-white/C/ch-1.c b/challenge-209/duncan-c-white/C/ch-1.c new file mode 100644 index 0000000000..41040f43df --- /dev/null +++ b/challenge-209/duncan-c-white/C/ch-1.c @@ -0,0 +1,105 @@ +// +// Task 1: Special Bit Characters +// +// C version. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "args.h" + + +// decode( bitlist ); +// apply the decoding rules to bitlist, modifying it. +// +void decode( char *bitlist ) +{ + // decode + bool changed = false; + do + { + changed = false; + + // decode 10 -> b + char *p = strstr( bitlist, "10" ); + if( p != NULL ) + { + printf( "found 10 in bitlist at %s, rewriting as b\n", p ); + *p = 'b'; + // shift rest of bitlist up one pos + for( char *s = p+1; (*s = *(s+1)) != '\0'; s++ ) /*EMPTY*/; + printf( "shifted bitlist up one %s\n", bitlist ); + changed = true; + continue; + } + // decode 11 -> c + p = strstr( bitlist, "11" ); + if( p != NULL ) + { + printf( "found 11 in bitlist at %s, rewriting as c\n", p ); + *p = 'c'; + // shift rest of bitlist up one pos + for( char *s = p+1; (*s = *(s+1)) != '\0'; s++ ) /*EMPTY*/; + printf( "shifted bitlist up one %s\n", bitlist ); + changed = true; + continue; + } + // decode 0 -> a + p = strchr( bitlist, '0' ); + if( p != NULL ) + { + printf( "found 0 in bitlist at %s\n", p ); + *p = 'a'; + printf( "altered bitlist to %s\n", bitlist ); + changed = true; + continue; + } + + } while( changed ); + printf( "modified bits: %s\n", bitlist ); +} + + +int main( int argc, char **argv ) +{ + int argno = process_flag_n_args( "spc", argc, argv, + 1, "bitlist" ); + + char *bitlist = argv[argno]; + + if( debug ) + { + printf( "bitlist: %s\n", bitlist ); + } + bool ok = true; + char badbit = 'a'; + for( char *s=bitlist; *s; s++ ) + { + if( *s != '0' && *s != '1' ) + { + ok = false; + badbit = *s; + } + } + if( ! ok ) + { + fprintf( stderr, "bad bit %c in %s\n", badbit, bitlist ); + exit(1); + } + + decode( bitlist ); + + if( debug ) + { + printf( "decoded bits: %s\n", bitlist ); + } + + int len = strlen(bitlist); + printf( "%d\n", bitlist[len-1] == 'a' ? 1 : 0 ); + return 0; +} diff --git a/challenge-209/duncan-c-white/C/csvsplit.c b/challenge-209/duncan-c-white/C/csvsplit.c new file mode 100644 index 0000000000..20e375dabb --- /dev/null +++ b/challenge-209/duncan-c-white/C/csvsplit.c @@ -0,0 +1,47 @@ +/* + * csvsplit.c: simple CSV splitting (csvForeach), useful utility function + * + * (C) Duncan C. White, May 2017 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <assert.h> + +#include "csvsplit.h" + + +/* + * csvForeach( csvstring, &foreach_callback, (void *)extravalue ); + * Split csvstring into each comma-separated field, calling the + * foreach calback for each comma-separated field, passing the + * value and extravalue as parameters to it. It doesn't deal + * with commas in quoted strings, however. + */ +void csvForeach( char *csvstring, csvforeachcb cb, void *extra ) +{ + // we need to modify the string, so make a mutable copy.. + char *copy = strdup( csvstring ); + + char *start = copy; + for(;;) + { + char *comma=strchr( start, ',' ); + if( comma != NULL ) + { + // found the first comma after start + *comma = '\0'; + } + //printf( "debug: csvForeach: found value %s\n", start ); + (*cb)( start, extra ); + + if( comma == NULL ) break; + + // move start to one beyond where comma was.. + start = comma+1; + } + // don't forget to.. + free( copy ); +} diff --git a/challenge-209/duncan-c-white/C/csvsplit.h b/challenge-209/duncan-c-white/C/csvsplit.h new file mode 100644 index 0000000000..c7f84857c1 --- /dev/null +++ b/challenge-209/duncan-c-white/C/csvsplit.h @@ -0,0 +1,14 @@ +/* + * csvsplit.h: simple CSV splitting (csvForeach) - doesn't handle + * quoted fields with nested commas. + * + * (C) Duncan C. White, May 2017 + */ + +// a csv foreach callback function takes +// a char * (the csv value split out) +// and a void * (an extra value). + +typedef void (*csvforeachcb)( char *, void * ); + +extern void csvForeach( char * csvstring, csvforeachcb cb, void * extra ); diff --git a/challenge-209/duncan-c-white/C/parseints.c b/challenge-209/duncan-c-white/C/parseints.c new file mode 100644 index 0000000000..80408d3382 --- /dev/null +++ b/challenge-209/duncan-c-white/C/parseints.c @@ -0,0 +1,114 @@ +// Simple routine to parse one or more arguments, +// looking for individual +ints or comma-separated +// lists of +ints. +// + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "args.h" +#include "printarray.h" +#include "parseints.h" + +typedef struct +{ + int nel; // current number of elements + int maxel; // maximum number of elements allocated + int *list; // malloc()d list of integers +} intlist; + + +// +// intlist il.. then initialize il.. then: +// add_one( element, &il ); +// +static void add_one( int x, intlist *p ) +{ + if( p->nel > p->maxel ) + { + p->maxel += 128; + p->list = realloc( p->list, p->maxel ); + assert( p->list != NULL ); + } + #if 0 + if( debug ) + { + printf( "PIA: appending %d to result at " + "pos %d\n", x, p->nel ); + } + #endif + p->list[p->nel++] = x; +} + + +// +// intlist il.. then initialize il.. then: +// add_one_arg( argstr, &il ); +// +static void add_one_arg( char *argstr, intlist *p ) +{ + int x; + if( !check_unsigned_int(argstr,&x) ) + { + fprintf( stderr, "PIA: arg %s must be +int\n", argstr ); + exit(1); + } + add_one( x, p ); +} + + +// +// int nel; +// int *ilist = parse_int_args( argc, argv, argno, &nel ); +// process all arguments argv[argno..argc-1], extracting either +// single ints or comma-separated lists of ints from those arguments, +// accumulate all integers in a dynarray list, storing the total number +// of elements in nel. This list must be freed by the caller. +// Note that the list of elements used to be terminated by a -1 value, +// but I've commented this out from now on. +// +int *parse_int_args( int argc, char **argv, int argno, int *nel ) +{ + int *result = malloc( 128 * sizeof(int) ); + assert( result != NULL ); + intlist il = { 0, 128, result }; + + #if 0 + if( debug ) + { + printf( "PIA: parsing ints from args %d..%d\n", argno, argc-1 ); + } + #endif + for( int i=argno; i<argc; i++ ) + { + assert( strlen(argv[i]) < 1024 ); + char copy[1024]; + strcpy( copy, argv[i] ); + char *com; + char *s; + for( s=copy; (com = strchr(s,',')) != NULL; s=com+1 ) + { + *com = '\0'; + add_one_arg( s, &il ); + } + add_one_arg( s, &il ); + } + + //add_one( -1, &il ); + + #if 0 + if( debug ) + { + printf( "PIA: final list is " ); + print_int_array( 80, il.nel, il.list, ',', stdout ); + putchar( '\n' ); + } + #endif + + *nel = il.nel; + return il.list; +} diff --git a/challenge-209/duncan-c-white/C/parseints.h b/challenge-209/duncan-c-white/C/parseints.h new file mode 100644 index 0000000000..da5e145a86 --- /dev/null +++ b/challenge-209/duncan-c-white/C/parseints.h @@ -0,0 +1 @@ +extern int * parse_int_args( int argc, char ** argv, int argno, int * nel ); diff --git a/challenge-209/duncan-c-white/C/printarray.c b/challenge-209/duncan-c-white/C/printarray.c new file mode 100644 index 0000000000..ddee597df3 --- /dev/null +++ b/challenge-209/duncan-c-white/C/printarray.c @@ -0,0 +1,39 @@ +#include <stdio.h> +#include <string.h> + + +// print_int_array( maxw, nelements, results[], sep, outfile ); +// format results[0..nelements-1] as a <sep> separated +// list onto outfile with lines <= maxw chars long. +// produces a whole number of lines of output - without the trailing '\n' +void print_int_array( int maxw, int nel, int *results, char sep, FILE *out ) +{ + int linelen = 0; + for( int i=0; i<nel; i++ ) + { + char buf[100]; + sprintf( buf, "%d", results[i] ); + int len = strlen(buf); + if( linelen + len + 2 > maxw ) + { + fputc( '\n', out ); + linelen = 0; + } else if( i>0 ) + { + fputc( ' ', out ); + linelen++; + } + + linelen += len; + fprintf( out, "%s", buf ); + if( i<nel-1 ) + { + fputc( sep, out ); + linelen++; + } + } + //if( linelen>0 ) + //{ + // fputc( '\n', out ); + //} +} diff --git a/challenge-209/duncan-c-white/C/printarray.h b/challenge-209/duncan-c-white/C/printarray.h new file mode 100644 index 0000000000..40efb83277 --- /dev/null +++ b/challenge-209/duncan-c-white/C/printarray.h @@ -0,0 +1 @@ +extern void print_int_array( int maxw, int nel, int * results, char sep, FILE * out ); diff --git a/challenge-209/duncan-c-white/README b/challenge-209/duncan-c-white/README index 80916b64a2..a7d82c8b31 100644 --- a/challenge-209/duncan-c-white/README +++ b/challenge-209/duncan-c-white/README @@ -1,86 +1,71 @@ -Task 1: Minimum Index Sum +Task 1: Special Bit Characters -You are given two arrays of strings. Write a script to find out all -common strings in the given two arrays with minimum index sum. If no -common strings are found returns an empty list. +You are given an array of binary bits that ends with 0. -Example 1 - -Input: @list1 = ("Perl", "Raku", "Love") - @list2 = ("Raku", "Perl", "Hate") - -Output: ("Perl", "Raku") +Valid sequences in the bit string are: -There are two common strings "Perl" and "Raku". -Index sum of "Perl": 0 + 1 = 1 -Index sum of "Raku": 1 + 0 = 1 +[0] -decodes-to-> "a" +[1, 0] -> "b" +[1, 1] -> "c" -Example 2 - -Input: @list1 = ("A", "B", "C") - @list2 = ("D", "E", "F") +Write a script to print 1 if the last character is an 'a' otherwise +print 0. -Output: () +Example 1 -No common string found, so no result. + Input: @bits = (1, 0, 0) + Output: 1 -Example 3 + The given array bits can be decoded as 2-bits character (10) followed + by 1-bit character (0). -Input: @list1 = ("A", "B", "C") - @list2 = ("C", "A", "B") +Example 2 -Output: ("A") + Input: @bits = (1, 1, 1, 0) + Output: 0 -There are three common strings "A", "B" and "C". -Index sum of "A": 0 + 1 = 1 -Index sum of "B": 1 + 2 = 3 -Index sum of "C": 2 + 0 = 2 + Possible decode can be 2-bits character (11) followed by 2-bits + character (10) i.e. the last character is not 1-bit character. -MY NOTES: very easy. Identify whether any common strings exist: set -intersection. Then calculate index sum of all common strings and choose -the minimum ones. Trickiest thing to work out is how to input two lists -of strings - let's choose an arbitrary separator ':'.. +MY NOTES: very easy. decode string then check last letter of decoded version. +I wonder if there's a way of decoding-and-checking together, though. GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl into C (look in the C directory for that). -Task 2: Duplicate and Missing +Task 2: Merge Account + +You are given an array of accounts i.e. name with list of email addresses. -You are given an array of integers in sequence with one missing and one -duplicate. Write a script to find the duplicate and missing integer in -the given array. Return -1 if none found. For the sake of this task, -let us assume the array contains no more than one duplicate and missing. +Write a script to merge the accounts where possible. The accounts can +only be merged if they have at least one email address in common. Example 1: - Input: @nums = (1,2,2,4) - Output: (2,3) + Input: @accounts = [ ["A", "a1@a.com", "a2@a.com"], + ["B", "b1@b.com"], + ["A", "a3@a.com", "a1@a.com"] ] + ] - Duplicate is 2 and Missing is 3. + Output: [ ["A", "a1@a.com", "a2@a.com", "a3@a.com"], + ["B", "b1@b.com"] ] Example 2: - Input: @nums = 1,2,3,4 - Output: -1 - - No duplicate and missing found. - -Example 3: - - Input: @nums = (1,2,3,3) - Output: (3,4) - - Duplicate is 3 and Missing is 4. + Input: @accounts = [ ["A", "a1@a.com", "a2@a.com"], + ["B", "b1@b.com"], + ["A", "a3@a.com"], + ["B", "b2@b.com", "b1@b.com"] ] -MY NOTES: also pretty easy - especially if the list of integers should (if it -were not for the one missing and one duplicated) form the sequence 1..N. -if so: the duplicate is the element where el[i] != i. -The missing is the sole member of set {1..N} - all el[i] + Output: [ ["A", "a1@a.com", "a2@a.com"], + ["A", "a3@a.com"], + ["B", "b1@b.com", "b2@b.com"] ] -Let's generalise it slightly to B, B+1, .. B+N-1. Then: find the element -where el[i] != el[0]+i, that is the duplicate, and the missing is the sole -member of {B..N+N-1} - all el[i] +MY NOTES: fiddly and rather inelegant, especially only being allowed to +merge two entries if the intersection of the email lists is non empty. +Will also need to choose an input format, how about a list of words of the +form A:a1@a.com,a2@a.com, B:b1@b.com, A:a3@a.com and B:b2@b.com,b1@b.com -GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl into C -(look in the C directory for that) +(TODO) GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl into C +(TODO) (look in the C directory for that) diff --git a/challenge-209/duncan-c-white/perl/ch-1.pl b/challenge-209/duncan-c-white/perl/ch-1.pl new file mode 100755 index 0000000000..8106040420 --- /dev/null +++ b/challenge-209/duncan-c-white/perl/ch-1.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl +# +# Task 1: Special Bit Characters +# +# You are given an array of binary bits that ends with 0. +# +# Valid sequences in the bit string are: +# +# [0] -decodes-to-> "a" +# [1, 0] -> "b" +# [1, 1] -> "c" +# +# Write a script to print 1 if the last character is an 'a' otherwise +# print 0. +# +# Example 1 +# +# Input: @bits = (1, 0, 0) +# Output: 1 +# +# The given array bits can be decoded as 2-bits character (10) followed +# by 1-bit character (0). +# +# Example 2 +# +# Input: @bits = (1, 1, 1, 0) +# Output: 0 +# +# Possible decode can be 2-bits character (11) followed by 2-bits +# character (10) i.e. the last character is not 1-bit character. +# +# MY NOTES: very easy. decode string then check last letter of decoded version. +# I wonder if there's a way of decoding-and-checking together, though. +# +# GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl into C +# (look in the C directory for that). +# + +use strict; +use warnings; +use feature 'say'; +use Getopt::Long; +use Data::Dumper; + +my $debug=0; +die "Usage: spc [--debug] list-of-bits\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV==1; + +my $bits = shift; +die "bad bit $1 in $bits\n" if $bits =~ /([^01])/; + +say "bits: $bits" if $debug; + +# decode +while( $bits =~ s/10/b/ || $bits =~ s/11/c/ || $bits =~ s/0/a/ ) +{ +} + +say "decoded bits: $bits" if $debug; + +say $bits =~ /a$/ ? 1 : 0; diff --git a/challenge-209/duncan-c-white/perl/ch-2.pl b/challenge-209/duncan-c-white/perl/ch-2.pl new file mode 100755 index 0000000000..e3cc27d87f --- /dev/null +++ b/challenge-209/duncan-c-white/perl/ch-2.pl @@ -0,0 +1,114 @@ +#!/usr/bin/perl +# +# Task 2: Merge Account +# +# You are given an array of accounts i.e. name with list of email addresses. +# +# Write a script to merge the accounts where possible. The accounts can +# only be merged if they have at least one email address in common. +# +# Example 1: +# +# Input: @accounts = [ ["A", "a1@a.com", "a2@a.com"], +# ["B", "b1@b.com"], +# ["A", "a3@a.com", "a1@a.com"] ] +# ] +# +# Output: [ ["A", "a1@a.com", "a2@a.com", "a3@a.com"], +# ["B", "b1@b.com"] ] +# +# Example 2: +# +# Input: @accounts = [ ["A", "a1@a.com", "a2@a.com"], +# ["B", "b1@b.com"], +# ["A", "a3@a.com"], +# ["B", "b2@b.com", "b1@b.com"] ] +# +# Output: [ ["A", "a1@a.com", "a2@a.com"], +# ["A", "a3@a.com"], +# ["B", "b1@b.com", "b2@b.com"] ] +# +# MY NOTES: fiddly and rather inelegant, especially only being allowed to +# merge two entries if the intersection of the email lists is non empty. +# Will also need to choose an input format, how about a list of words of the +# form A,a1@a.com,a2@a.com, B,b1@b.com, A,a3@a.com and B,b2@b.com,b1@b.com +# +# (TODO) GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl into C +# (TODO) (look in the C directory for that) +# + +use strict; +use warnings; +use feature 'say'; +use Getopt::Long; +use Data::Dumper; + +my $debug=0; +die "Usage: merge-accounts [--debug] name,emails+\n" + unless GetOptions( "debug"=>\$debug ) && @ARGV > 0; + +my @input = map { + my @x = split( /,/ ); + \@x; +} @ARGV; + +#say "input: ", Dumper(\@input) if $debug; + +my %names = map { $_->[0] => 1 } @input; +my @names = sort keys %names; +#say "names: ", Dumper(\@names) if $debug; + + +# +# my @out = merge( $name, @input ); +# Take $name, and @input, all the $name->email-set rules +# and merge as many as possible of the email-sets, returning +# one or more name,email-set results. +# +sub merge +{ + my( $name, @input ) = @_; + @input = map { my @m = @$_; shift @m; \@m } @input; + say "name $name: ", Dumper(\@input) if $debug; + my @result; + for( my $i=0; $i<@input; $i++ ) + { + my $aref = $input[$i]; + say "i $i, name $name: ", Dumper($aref) if $debug; + my %mem = map { $_ => 1 } @$aref; + + # ok, check through all later inputs, trying to merge + # them into $aref (deleting them from @input) if we manage. + for( my $j=$i+1; $j<@input; $j++ ) + { + my $bref = $input[$j]; + say "j $j, name $name: ", Dumper($bref) if $debug; + if( grep { $mem{$_} } @$bref ) # can merge + { + map { $mem{$_}++ } @$bref; + splice( @input, $j, 1 ); # remove this + say "merged j $j into i $i" if $debug; + } + } + + # turn %mem back into a list + my @list = sort keys %mem; + + push @result, [ $name, @list ]; + } + return @result; +} + + +my @output = map { + my $name = $_; + merge( $name, grep { $_->[0] eq $name } @input ); + } @names; + +print "output: [ "; +print join( ', ', + map { "[" . + join( ', ', + map { qq("$_") } @$_ + ). "]"; } @output ); +say " ]"; |
