Anzahl Elemente in Array hochzählen

Dieses Thema im Forum "Shell-Skripte" wurde erstellt von h.nietnagel, 28.07.2010.

  1. #1 h.nietnagel, 28.07.2010
    h.nietnagel

    h.nietnagel Grünschnabel

    Dabei seit:
    28.07.2010
    Beiträge:
    9
    Zustimmungen:
    0
    Hallo zusammen,

    nach etwa 20 Stunden unermüdlichen Probierens, komme ich jetzt doch nicht am Nachfragen vorbei :-(

    Ich möchte ein Array von 16 Dateinamen erstellen, die eine Zahl enthalten (zwischen 0 und 15), die zufällig vergeben werden soll, allerdings soll jede nur einmal vergeben werden.
    Wenn ich einen "break" einfüge, nachdem die Zahl zweimal vorkommt, dann wird dieser ignoriert und die Zahl kann häufiger vergeben werden, wenn ich einen "break 2" einfüge, dann enthält mein Array zum Schluss weniger als die 16 Einträge.
    Wo liegt mein Denkfehler?
    PHP:
    #!/bin/bash
    #Program to crop the picture and resamble the pieces
    declare -a ListPartPics

    #convert testa.png -crop 25% %d_test.png 

    Max=15
    count
    =-1  

    noEntries
    =16
    while [ $count -lt $Max ]  ## ${#ListPartPics[$noEntries]}
          
    do
            
    count=$[$count+1]  # increment the counter by 1
            
    let "zahl = $RANDOM % $Max + 1" 
            
    echo "Hier lautet die zahl:" $zahl
            i
    =0    
            
    for i in ${ListPartPics[@]}
            do
            echo 
    "This is i:" $i        
            
    if [[ $zahl ==  $i ]]
            
    then  
            count
    =$[$count-1# set the counter back to the preceding one
            
    echo "this is count number in the if loop: set back by 1: " $count
            
    break 2                     
            fi                     
            done    
    ListPartPics
    [$count]=$zahl 
    echo "this is count number" $count
    echo ${ListPartPics[$count]}"_test.png" 
    done

    echo "Anzahl Elemente in der Liste:" ${#ListPartPics[@]}
    echo "these are the picture numbers being used:" ${ListPartPics[@]}
    Vielen Dank im Voraus für Tipps!

    Hannes
     
  2. Anzeige

    Schau dir mal diese Kategorie an. Dort findest du bestimmt etwas.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  3. #2 bytepool, 28.07.2010
    Zuletzt bearbeitet: 28.07.2010
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Hi,

    ich hab auch eine Weile gebraucht um dahinter zu steigen was da falsch laeuft, aber vor allem weil der debug output ein wenig schlecht formatiert war, und ich den Algorithmus auch sehr ungewoehnlich finde. ;)

    Das Problem ist ganz einfach, dass du nach einem break die letzte Zahl im Array ueberschreibst, weil du nicht checkst ob ein break ausgefuehrt wurde oder nicht. Eine einfache if Abfrage vor der Zuweisung loest das Problem:
    PHP:
    #!/bin/bash
    #Program to crop the picture and reassemble the pieces
    declare -a listPartPics

    max
    =15
    count
    =-1

    while [ $count -lt $max ]; do

       
    count=$((count 1))
       
    modulo=$((max+1))

       
    let "number = $RANDOM % $modulo"
       
    broke=0

       
    echo -"\n----new while iteration----"
       
    echo "number: $number"
       
    echo '${listPartPics[@]}:' ${listPartPics[@]}

       for 
    i in ${listPartPics[@]}; do
           echo -
    "i:" $i ", "
           
    if [ $number -eq  $i ]; then
               count
    =$((count 1))
               
    broke=1
               
    break
           
    fi
       done

       
    if [ $broke -eq 0 ]; then
           listPartPics
    [$count]=$number
       fi
       
    echo -"\ncount: " $count
       
    echo ${listPartPics[$count]}"_test.png"
    done

    echo -"\nAnzahl Elemente in der Liste:" ${#listPartPics[@]}
    echo "These are the picture numbers being used:" ${listPartPics[@]}
    Ich guck mal ob ich gleich noch Lust hab das Program etwas leserlicher zu schreiben. In Python saehe eine simple Variante so aus:
    PHP:
    import random

    numbers 
    = []
    files = []
    max 15

    for i in range(0max 1):
        
    numbers.append(i)

    for 
    i in range(0max 1):
        
    number random.choice(numbers)
        
    numbers.remove(number)
        
    files.append(str(number) + "_filename")

    print 
    files
    Aber das laesst sich leider nicht 1 zu 1 fuer die Bash ubernehmen. ;)

    Edit:
    Mhh, wer haette gedacht, dass das so schwierig ist. Da die Bash keine Membership Funktionen oder so etwas simples wie array.remove(element) kennt, muss man einige Umwege gehen:
    PHP:
    #!/bin/bash

    # generally, 0 means success, and 1 is an error
    # so a return value of 1 means that param 1 ($1)
    # does not match any of the following parameters
    function isMember
    {
        
    item=$1
        
    array=( $@ )

        if [ ${
    #array[@]} -le 1 ]; then
            
    return 1
        fi

        
    # delete param 1 from the array
        
    array[0]=; array=( ${array[@]} )

        
    # check for membership
        
    for number in ${array[@]}; do
            if [ 
    $number -eq $item ]; then
               
    return 0
            fi
        done

        
    return 1
    }

    max=15
    modulus
    =$((max 1))

    # fill array $numbers
    for ((0<= $max1)); do
        
    numbers[$i]=$i;
    done

    for ((0<= $max1)); do
       
    # find a number which has not been used yet
       
    let "rand = $RANDOM % $modulus"
       
    while isMember $rand ${result[@]}; do
           
    let "rand = $RANDOM % $modulus"
       
    done

       result
    [$i]=$rand

       
    # remove $rand from $numbers
       
    for ((0< ${#numbers[@]}; j = j + 1)); do
           
    if [ ${numbers[j]} -eq $rand ]; then
               numbers
    [j]=; numbers=( ${numbers[@]} )
               break
           
    fi
       done
    done

    echo "result: ${result[@]}"
    Ob das jetzt wirklich eleganter ist, ist wohl Geschmacksache, das waere jedenfalls mein Ansatz gewesen. ;)

    mfg,
    bytepool
     
  4. #3 h.nietnagel, 29.07.2010
    Zuletzt bearbeitet: 29.07.2010
    h.nietnagel

    h.nietnagel Grünschnabel

    Dabei seit:
    28.07.2010
    Beiträge:
    9
    Zustimmungen:
    0
    Hi bytepool,

    vielen Dank für die schnelle Hilfe! :respekt:
    Ähm *rotwerd* für mich ist (Shell)Programmierung Neuland und Schwerstarbeit. Ich hab mir überall dort was ausgeben lassen, wo ich dachte, dass es mir bei der Fehlersuche hilft. :hilfe2:
    Mich hatte der Gedanke an die Abfrage der breaks gestreift, leider wusste ich das aber nicht umzusetzen.

    Aber irgendwie funktioniert es noch nicht ganz. Die Anzahl der Listeneinträge ist 16, aber irgendwie werden Zahlen doppelt ausgegeben. :think:

    Ähm, jetzt bist Du mir mit Deinem Edit gerade zuvor gekommen... ;-)
    Das teste ich gleich mal.

    Vielleicht sollte ich gleich auf Python umsteigen, bevor ich mich weiter in die Bash hineinwühle...
    .
    .
    .
    EDIT (autom. Beitragszusammenführung) :
    .

    perfetto! :respekt:
    Es funktioniert ausgezeichnet! Allerdings ist das Skript jetzt schon sehr advanced. Tausend Dank, ich hätte es allein niemals hinbekommen!
     
  5. #4 floyd62, 29.07.2010
    floyd62

    floyd62 Routinier

    Dabei seit:
    01.05.2007
    Beiträge:
    309
    Zustimmungen:
    0
    Hi,

    wollte nur kurz auch meinen Senf dazugeben ;)

    Vorschlag: wenn ein Array so einfach aufgebaut ist (z.B. wie hier nur Zahlen enthält), dann kann man auch mit einer simplen 'case'-Abfrage überprüfen, ob eine bestimmte Zahl darin enthalten ist. Damit wird eine Schleife über die einzelnen Elemente unnötig, und man kann im Fall eines Duplikats mit 'continue' direkt den nächsten Durchlauf der umfassenden 'while'-Loop starten (eine neue Zufallszahl holen), also etwa:

    Code:
    #!/bin/bash
    
    noEntries=16
    
    count=0
    while [ $count -lt $noEntries ]; do
            random=$(($RANDOM % $noEntries))
    
            case " ${numbers[@]} " in *" ${random} "*) continue ;; esac
    
            numbers[$count]=${random}
            files[$count]=${random}_test.png
    
            let count++
    done
    
    echo NUMBERS: ${numbers[@]}
    echo FILES: ${files[@]}
    
    (NB: Wenn man den Zähler '$count' erst am Ende der Loop hochzählt, also nachdem der $RANDOM-Generator eine _neue_ Zahl geliefert hat, erspart man sich auch das Korrigieren im Fall eines Duplikats.)

    Gruss
     
  6. #5 bytepool, 29.07.2010
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Hi,

    Das gepostete Programm funktioniert hier prima. Wenn du die Aenderungen von Hand gemacht hast, hast du sicherlich nur noch was vergessen.

    Gern geschehen, aber dein Programm funktionierte ja auch schon fast, fehlten doch nur noch 5 Zeilen, da waerst du sicherlich irgendwann auch noch drauf gekommen. ;)

    Joa, und wie man an floyd's Beispiel sieht, ist die heransgehensweise fuer die Bash auch eher ungeeignet, geht viel einfacher mit deiner Heransgehensweise.
    Das war mehr der Versuch den Algorithmus aus Python in die Bash zu uebertragen. Ich hab in der Bash noch nicht viel mit Arrays gemacht, deswgen dachte ich mir, ich guck mir das mal an.

    Kommt drauf an was du vor hast, hat beides Vor- und Nachteile. Manche Dinge gehen mit einer kompletteren Skriptsprache schneller und leichter, und manche Dinge gehen schneller in der Bash.

    @floyd62
    Na, das sieht doch schon besser aus, da ist die Einfachheit und Eleganz die ich suchte. ;)
    Nebenbei, wenn wir eh schon alle let's eleminieren, "let count++" kann man auch einfach als "((count++))" schreiben.

    mfg,
    bytepool
     
  7. #6 floyd62, 29.07.2010
    floyd62

    floyd62 Routinier

    Dabei seit:
    01.05.2007
    Beiträge:
    309
    Zustimmungen:
    0
    @bytepool

    Merci, das "((count++))" kannte ich noch nicht; man lernt doch nie aus ;)

    Grüsse, A.
     
  8. #7 h.nietnagel, 29.07.2010
    Zuletzt bearbeitet: 29.07.2010
    h.nietnagel

    h.nietnagel Grünschnabel

    Dabei seit:
    28.07.2010
    Beiträge:
    9
    Zustimmungen:
    0
    Hallo,

    vielen Dank für die viele Mühe!
    Und das kurze, knackige Skript von floyd62 ist der Hammer. Ich wär froh, wenn ich sowas auch programmieren könnte. Hab viel dabei gelernt!

    Und es auch hübsch angepasst. Nur leider wieder mit einem bug. Es ist zum heulen! X(

    Ich poste der Einfachheit halber mal alles (auch wenn das nicht ganz im Sinne der Forumregeln ist :headup:), nicht dass ich versehentlich den Teil mit dem bug auslasse.
    PHP:
    #!/bin/bash

    declare -a eqORgt
    eqORgt
    =("-eq" "-gt");

    for 
    k in *.tif; do
            
    op=$(($RANDOM % ${#eqORgt[@]}))
    noEntries=25
    count
    =0

    convert $k 
    -resize 50x35 r${k%.*}.png
    convert $ECHO 
    "r${k%.*}.png" -crop 20% %d_mask.png 
    while [ $count -lt $noEntries ]; do
            
    random=$(($RANDOM $noEntries))

            case 
    ${numbers[@]} " in *${random} "*) continue ;; esac

            numbers
    [$count]=${random}
            
    files[$count]=${random}_mask.png
            let Even
    =$random%2
            
    if [ $Even ${eqORgt[op]} ] ; then
            convert 
    -rotate 180 $ECHO "${files[$count]}$ECHO "${files[$count]}"fi        
            let count
    ++        
    done

    echo NUMBERS: ${numbers[@]}
    echo 
    FILES: ${files[@]}

    convert \( $ECHO "${files[0]}$ECHO "${files[1]}$ECHO "${files[2]}$ECHO "${files[3]}$ECHO "${files[4]}+append \) \( $ECHO "${files[5]}$ECHO "${files[6]}$ECHO "${files[7]}$ECHO "${files[8]}$ECHO "${files[9]}+append \) \( $ECHO "${files[10]}$ECHO "${files[11]}$ECHO "${files[12]}$ECHO "${files[13]}$ECHO "${files[14]}+append \) \( $ECHO "${files[15]}$ECHO "${files[16]}$ECHO "${files[17]}$ECHO "${files[18]}$ECHO "${files[19]}+append \) \( $ECHO "${files[20]}$ECHO "${files[21]}$ECHO "${files[22]}$ECHO "${files[23]}$ECHO "${files[24]}+append \) -append r${k%.*}_mask.png 

    rm $ECHO 
    ${files[@]}
    mv $ECHO "r${k%.*}_mask.png" PicturesResized/.
    mv $ECHO "r${k%.*}.png" PicturesResized/.
    done
    Für das erste Bild wird das alles hübsch gemacht, aber dann scheint sich das Programm aufzuhängen. Ich habe nirgendwo einen Hinweis gefunden, dass man in eine for- Schleife keine while- Schleife einbauen kann. Das wär jetzt meine Vermutung für den bug gewesen. ?(
    Und da das Programm für das erste Bild im Ordner ohne Fehlermeldung durchläuft, frage ich mich, wo der Aufhänger sein soll.

    Habt ihr noch einen heißen Tipp?

    Tausend Dank für die Hilfe!!!

    Schöne Grüße,
    Hannes
     
  9. Anzeige

    Vielleicht findest du HIER Antworten.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  10. #8 floyd62, 29.07.2010
    floyd62

    floyd62 Routinier

    Dabei seit:
    01.05.2007
    Beiträge:
    309
    Zustimmungen:
    0
    Hi,

    versuch mal, ob es ausreicht unter der Zeile 10(?)
    Code:
            count=0
    
    noch die Zeilen
    Code:
            numbers=()
            files=()
    
    zu ergänzen ... sieht für mich so aus, als ob der nach dem ersten Durchlauf die numbers und files Arrays nicht leermacht, und dann hängt das Skript natürlich beim Erzeugen der neuen Zufalls-Folge, weil er ja alle Zahlen schon mal gesehen hat ...

    Gruss,
    A.
     
  11. #9 h.nietnagel, 30.07.2010
    h.nietnagel

    h.nietnagel Grünschnabel

    Dabei seit:
    28.07.2010
    Beiträge:
    9
    Zustimmungen:
    0
    Hallo,

    Ähm, ja. Das reicht aus. :D
    Darauf hätte ich natürlich auch kommen können... den Zähler hab ich ja immerhin brav auf Null gesetzt.

    Vielen Dank nochmals!


    Schöne Grüße,
    Hannes
     
Thema: Anzahl Elemente in Array hochzählen
Besucher kamen mit folgenden Suchen
  1. bash array hochzählen

Die Seite wird geladen...

Anzahl Elemente in Array hochzählen - Ähnliche Themen

  1. Steam: Anzahl an Linux-Spielen vervierfacht sich

    Steam: Anzahl an Linux-Spielen vervierfacht sich: Seit der Veröffentlichung von Steam für Linux vor einem Jahr hat sich die Zahl der Titel für Linux vervierfacht. Auch die Qualität der Titel...
  2. Anzahl Blöcke Unix-Dateisystem berechnen

    Anzahl Blöcke Unix-Dateisystem berechnen: Hi, Ich möchte folgende Aufgabe berechnen: Die Blockgröße eines Unix-Dateisystems beträgt 4 kiByte. Die indirekten Blöcke enthalten 1024...
  3. Anzahl Dateein in xbeliebigen Verzeichnissen ermitteln

    Anzahl Dateein in xbeliebigen Verzeichnissen ermitteln: Hallo ixh habs mal in diese Rubrik gesetzt, da ich nciht weiß, ob das nur per script geht, oder nicht. Wie kann ich die Anzahl der Dateien...
  4. Anzahl der belegten Speicherbänke in der Konsole anzeigen

    Anzahl der belegten Speicherbänke in der Konsole anzeigen: Moin, gibt es eine Möglichkeit über die Konsole herauszufinden, wie viele RAM Module in meinem System verbaut sind? mfg thobit
  5. Anzahl von Buchstaben (-paare, -tripel) aus Text auslesen

    Anzahl von Buchstaben (-paare, -tripel) aus Text auslesen: Hi Leute, Ich steige gerade in Unix ein, und versuche einige Aufgaben zu lösen. Derzeit stehe ich vor der Aufgabe aus einem Text (ein ganzes Buch...