Erhalten Sie 100 Palindromzahlen

7

Ich bin neu im Scripting und habe diese Aufgabe, 100 Palindromzahlen mit dem folgenden Algorithmus zu finden:

  1. Erhalten Sie eine zweistellige Zufallszahl (größer als 10)
  2. Kehren Sie die Nummer um
  3. Summiere die Zahl und ihre Umkehrung
  4. Wenn das Ergebnis der Summe eine Palindromzahl ist, drucken Sie sie aus. Andernfalls kehren Sie zu Schritt 2 zurück

Zum Beispiel:

  • Startnummer: 75
  • Rückwärts ist 57
  • Die Summe beträgt 75 + 57 = 132

Da 132 keine Palindromzahl ist, fahren Sie mit Schritt 2 fort:

  • Rückwärts ist 321
  • 132 + 321 = 363
  • 363 ist eine Palindromzahl. Drucken Sie es auf stdout!

Und so weiter, bis 100 dieser Zahlen gedruckt werden.


Das habe ich bisher:

#! /bin/bash

CONT=0
while [ $CONT -lt 100 ] 
do
    NUM= $RANDOM
    while [ $SUM -ne $SUMINV ] 
    do

        echo $NUM > file.txt
        INV= rev file.txt
        SUM= `expr[ $NUM + $INV ]`
        echo $SUM > file2.txt
        SUMINV= rev file2.txt
        NUM= $SUM
    done
    echo $NUM
    CONT=`expr $CONT + 1`
done

Suchen Sie nach Lösungen und helfen Sie mit diesem Skript!

Panama
quelle
Ich hatte Fehler beim Ausführen Ihres Skripts, daher wurden einige Syntax- und Konventionsprobleme im Code behoben. Sehen Sie, ob es jetzt funktioniert. Wenn es sich um eine Aufgabe handelt, würde ich vorschlagen, dass Sie sie selbst bekämpfen.
mkc
8
@ Ketan bitte niemals, niemals Syntaxfehler in der Frage beheben. Das sollte in einer Antwort geschehen. Wenn Sie die Fehler beheben, kann die Frage selbst keinen Sinn ergeben, da wir nicht verstehen können, was mit dem OP-Skript nicht stimmt. In jedem Fall hat Ihre Bearbeitung immer noch Syntaxfehler hinterlassen, was sie noch weniger nützlich macht :)
terdon
@terdon Ok, verstanden.
mkc

Antworten:

1

Wie ich zunächst verstehe, müssen Sie eine zweistellige Nummer erhalten, die

  • größer 10 und kleiner 100
  • nicht durch 10 geteilt (Nr. 20; 30; usw.)
  • ist kein Palindrom (Nr. 22; 33; usw.)

So können Sie es erreichen

while :
do
  a=$[$RANDOM%10]
  b=$[$RANDOM%10]
  if [ $a -ne $b -a $a -ne 0 -a $b -ne 0 ]
  then
    NUM="$a$b"
    RNUM="$b$a"
    break
  fi
done

Nächster Schritt, um die Summe der Zahlen und ihre Umkehrung zu überprüfen

while :
do
  NUM=$[$NUM+$RNUM]
  RNUM=$(printf "%d" $NUM | rev)
  if [ $NUM -eq $RNUM ]
  then
    echo $NUM
    break
  fi
done
Costas
quelle
Das OP möchte Palindrome ("Wenn das Ergebnis der Summe eine Palindromzahl ist, drucken Sie sie aus. Andernfalls zurück zu Schritt 2") und soweit ich das beurteilen kann, haben sie keine Einschränkung, ob die Zahl durch 10 teilbar ist Ein cleverer Trick, um die zweistelligen Zahlen zu erhalten.
Terdon
@terdon Was mich betrifft, gibt es keinen Sinn in Zahlen, die durch 10 teilbar sind, genauso wie Palindrome, selbst wenn es den einfachen Weg macht, eine zweistellige Zahl von$RANDOM%100
Costas
1

In Ihrem ursprünglichen Skript gab es verschiedene Syntaxfehler. Zum Beispiel foo= barist falsch, Leerzeichen sind wichtig in Bash. Du brauchst foo=bar. Um die Ausgabe eines Befehls zu erhalten, können foo=commandSie den Befehl nicht in Backticks oder besser einschließen foo=$(command). Hier ist eine Arbeitsversion:

#!/usr/bin/env bash
CONT=0

## This array will hold the numbers we've seen
## uncomment this line for unique numbers
#declare -a seen;
while [ "$CONT" -lt 100 ] 
do
    ## Get a random number
    NUM=$RANDOM
    ## Make sure it is < 100
    let "NUM %= 100"
    ## Make sure the number is more than 10
    while [ "$NUM" -le 10 ]
    do
        NUM=$((NUM+1))
    done
    ## In case the addition made it longer than two digits
    NUM="${NUM:0:2}"
    ## Make sure the number does not end in 0
    ## If it does, we will get an error when
    ## attempting to add it. Bash doesn't
    ## like leading 0s. 
    [[ $NUM =~ 0$ ]] && let NUM++
    ## Sum the number and its reverse
    SUM=$((NUM+$(rev <<<$NUM)));

    ## Is this a palindrome?
    if [ "$SUM" = "$(rev <<<$SUM)" ]
    then
        ## You did not say if you wanted 100 different
        ## numbers. If so, uncomment these lines
        #let seen[$SUM]++
        ## If this number has not been seen before
        #if [ "${seen[$SUM]}" -eq 1 ]
        #   then
        ## print it
        echo $SUM
        ## increment the counter
        let CONT++
        #fi
    fi
done

Beachten Sie, dass das Skript die Zahlen unverändert wiederholt. Um eindeutige Zahlen zu erhalten, kommentieren Sie die Zeilen wie in den Kommentaren des Skripts beschrieben aus.

terdon
quelle
1

Dieser macht Spaß. Ich mag diese Frage. Ich habe die folgende Funktion geschrieben, um die Aufgabe auszuführen, und sie erledigt den Job.

palindromes() (
rev()   while getopts : o "-$1" ||
        ! r="${2#"${2%%[1-9]*}"}"
        do set -- "$1" "$OPTARG$2"
        done
rand()  { : & : "$(($1=$!))"; }

[ "$1" -gt 10 ] || exit
n=$1; set --
while OPTIND=1; rev "$n"
        case "$#.$n.$r"                              in
        (100.*) ! printf '%s\t%s\t%s\t%s\t%s\n' "$@" ;;
        (*.$r.$n) set -- "$@" "$n"; rand n           ;;
        (*)       n=$((${n#-}+${r%-}))               ;;
esac; do :; done
)

Es gibt ein paar Dinge, die daran bemerkenswert sind. In erster Linie getoptswird verwendet, um die Zahl umzukehren. Die Hauptfunktion von getoptsbesteht darin, kurze Optionen zu analysieren, die möglicherweise alle aneinandergereiht sind oder nicht - und ist daher ein praktisches Werkzeug zum Durchlaufen jedes Bytes in einer Zeichenfolge.

Ich mag die $RANDFunktion der bashShell nicht sehr , aber wahrscheinlich ist sie konservativer als meine rand()Funktion, die nur eine No-Op-Task hinterlegt und ihre nicht mehr existierende PID dem in ihrem ersten Argument gespeicherten Variablennamen zuweist. Ziemlich billig, das gebe ich zu.

Das caseKonstrukt kann in einem einfachen Test leicht alle Facetten Ihrer Aufgabe bewerten. Ich mache:

case "$#.$n.$r" in 
(100*) all done; printf %s\\n "$@";; 
(*$r.$n) palindrome; set -- "$@" "$n";;
(*) no luck; $n+$r; go again;;
esac

Ich hatte anfangs große Schwierigkeiten damit. Zuerst habe ich Sachen gemacht wie:

(*$r.$n) set -- ...; n=$((n+1))

Das war eine schlechte Idee. Die außer Kontrolle geratene Addition vergrößerte die Zahlen sofort auf Größen, bei denen die bloße Anzahl der Ziffern ausreichte, um die Wahrscheinlichkeit zu verringern, jemals ein Palindrom zu finden. Ich habe herumgespielt, date +%Saber ich dachte mir, wenn ich trotzdem einen anderen Prozess ausführen würde, könnte ich genauso gut die PID verwenden. Und dieser Prozess könnte in diesem Fall genauso gut ein Null-Op sein. Wie auch immer, der PID-Bereich ist klein genug, um so ziemlich jedes Mal im Runaway-Faktor zu regieren, wie es scheint.

Zum Beispiel werde ich dies jetzt ausführen und die Ergebnisse einfügen:

palindromes 76

AUSGABE

484     29292   49294   69296   89298
215512  50605   90609   446644  886688
123321  52625   92629   468864  663787366
134431  54645   94649   881585188       7667585634365857667
145541  23432   43434   63436   83438
147741  24442   44444   64446   84448
158851  25452   45454   65456   85458
169961  13231   46464   66466   86468
49985258994     27472   47474   67476   87478
14355341        28482   48484   68486   88488
395593  29492   49494   69496   89498
219912  121121  11244211        441144  881188
125521  165561  15522551        463364  7365409856589045637
136631  211112  17858768886785871       485584  893974888888479398
147741  23632   43634   63636   83638
149941  24642   44644   64646   84648
523325  25652   45654   65656   85658
567765  13331   46664   66666   86668
2358532 27672   47674   67676   87678
2236322 28682   48684   68686   88688

Es sind wahrscheinlich einige Dupes drin - es passiert anscheinend. Nicht viele. Ich weiß nicht, ob das ein Problem für Sie ist oder nicht, aber dies ist nur ein Beispiel dafür, wie es gemacht werden könnte.

Ein letzter Hinweis: Das Ausführen dashist weitaus schneller als das Einführen bash. obwohl der Unterschied nur eine Sekunde oder so zu sein scheint. In jedem Fall müssen Sie , wenn Sie verwenden dash, die rev() set -- "$1"Zeile in ändernset -- "${1#?}".

Ich habe gerade festgestellt, dass es eine zweistellige Anforderung gibt - obwohl ich den Verdacht habe, dass diese spezielle Regel ein Versuch ist, zu verhindern, dass die Aufgabe zu schwierig wird. Auf jeden Fall ist es sehr einfach, nur eine Teilmenge eines Strings abzurufen. In der Tat ist es das, womit ich mache, r=wenn ich:

r="${2#"${2%%[1-9]*}"}"

... die immer reinen Wert zuweist , der nicht mit einer Null beginnt.

Hier ist eine Version davon rand(), die immer eine zweistellige Nummer zuweist $1:

rand() { : & set -- "$1" "$!" "$(($!%100))"
         : "$(($1=($3>10?$3:${#2}$3)))"
}

Sie können natürlich die gleiche Logik auf bash's anwenden $RAND. Der $((var=(value)?(assign if true):(assign if false)))"ternäre Operator arbeitet mit nahezu jeder Ganzzahl. Hier weise ich ihm entweder das Modulo 100 (im Grunde genommen ein Perzentil) zu, wenn dieser Wert größer als zehn ist, oder ich weise das als zweite von zwei Ziffern zu, wobei die erste eine Zählung der Ziffern in ist $!.

Laufen Sie so und die Ergebnisse sind etwas weniger aufregend:

333     66      484     1111    4884
77      88      99      121     121
363     484     77      4884    44044
88      99      121     121     363
484     1111    4884    88      8813200023188
99      121     121     363     484
1111    4884    44044   8813200023188   99
44      55      66      77      44
99      121     121     363     484
424     11      33      44      55
66      77      88      99      121
22      33      22      55      66
77      88      99      121     121
33      44      55      33      77
88      99      121     121     363
44      55      66      77      44
99      121     121     363     484
55      66      77      88      99
55      121     363     484     1111
66      77      88      99      121
mikeserv
quelle