Permutációk kiíratása bash-ban

Kezdőlap Fórumok Programozás Permutációk kiíratása bash-ban

7 bejegyzés megtekintése - 1-7 / 7
  • Szerző
    Bejegyzés
  • #2126967
    xcut
    Felhasználó

      bash-ban annyira nem vagyok jó, hogy ilyeneket írjak, de valahogy úgy kellene nekiállni, mint ahogyan a bicikln működik a számzár. Szóval kell egy két dimenziós tömb, és azokban kell iterálgatni végig. Valami ilyesmit képzelj el (php):

      Code:
      $tomb[]=array(‘lehetoseg0’, ‘lehetoseg1’, ‘lehetoseg2’);

      Ha ez megvan, akkor szépen csak végig kell rajta menni, és legenrálni a lehetőségeket.

      #2126968
      xcut
      Felhasználó

        bash-ban annyira nem vagyok jó, hogy ilyeneket írjak, de valahogy úgy kellene nekiállni, mint ahogyan a bicikln működik a számzár. Szóval kell egy két dimenziós tömb, és azokban kell iterálgatni végig. Valami ilyesmit képzelj el (php):

        Code:
        $tomb[]=array(‘lehetoseg0’, ‘lehetoseg1’, ‘lehetoseg2’);

        Ha ez megvan, akkor szépen csak végig kell rajta menni, és legenrálni a lehetőségeket.

        #2126969
        uzsolt
        Felhasználó

          Ez a progi is ezt csinálja/csinálná lényegében. Ha esetleg segít, és valaki valamit észrevesz, akkor egy kicsit kommentelem:

          #!/bin/bash

          if [ $# -eq 0 ]; then exit ; fi

          # Hány mezőre bomlik – csak a vesszőket hagyjuk a szövegben, és a karaktereket megszámoljuk (wc), de előtte még töröljük az újsor-karaktert (tr)
          FIELD_NR=$(echo $* | grep -o „,” | tr -d „n” | wc -m)
          FIELD_NR=$((FIELD_NR + 2)) # Nem igazán értem, miért +2 kell, miért nem +1

          # Egy ideiglenes fájlt csinálunk
          TEMPFILE=$(mktemp)

          # A paramétert a „vesszőknél fogva” sorokra tördeljük (awk), az elején levő felesleges szóközöket töröljük (sed) és a TEMPFILE-ba írjuk
          echo $* | awk -F „,” {‘for (i=1;i $TEMPFILE

          # A rekurzív függvénykém
          # Hívása: Permutacio hanyadik_szint eddig_generált_karakter_sor
          function Permutacio () {

                  # Lokális változók…
                  local level
                  local CUR_ROW
                  local i

                  # Az első paramétert eltároljuk, majd őt „kilökjük” (shift), hogy ne zavarjon bele a generált szövegbe
                  level=$1
                  shift

                  # Ha elértük a „bűvös” szintet, akkor az eddig generált karaktersort kiírjuk, és nem rekurvulunk tovább
                  if [ $level -eq $FIELD_NR ]; then
                          echo $*
                          break
                  fi

                  # A level sorszámú („leveledik” 😉 ) sort kiszedjük a fájlból (sed)
                  CUR_ROW=$(sed -n „${level}p” $TEMPFILE)
                  # A level-t eggyel növeljük – bár szerintem ezt a megjegyzést nem is kellett volna ideírni 🙂
                  level=$((level+1))

                  # Az aktuális sor szóközökkel elválasztott szavain szalad végig az i változó
                  for i in $CUR_ROW ; do
                          # Rekurzió, a már megnövelt level-lel, az eddig kapott karaktersor ($*) kibővítve az aktuális „szóval” ($i)
                          Permutacio $level $* $i
                  done
          }

          # Rekurzió elkezdése level=1-gyel és üres sorozattal
          Permutacio 1

          # Szerintem az uccsó sor nem szorul magyarázatra
          rm $TEMPFILE

          Próbáltam én debuggolni (különféle echo-üzik), de mintha az történne, hogy a legutolsó szintű for-cikluson nem halad végig, csak az első elemre hajtja végre a ciklusmagot…

          #2126970
          uzsolt
          Felhasználó

            Ez a progi is ezt csinálja/csinálná lényegében. Ha esetleg segít, és valaki valamit észrevesz, akkor egy kicsit kommentelem:

            #!/bin/bash

            if [ $# -eq 0 ]; then exit ; fi

            # Hány mezőre bomlik – csak a vesszőket hagyjuk a szövegben, és a karaktereket megszámoljuk (wc), de előtte még töröljük az újsor-karaktert (tr)
            FIELD_NR=$(echo $* | grep -o „,” | tr -d „n” | wc -m)
            FIELD_NR=$((FIELD_NR + 2)) # Nem igazán értem, miért +2 kell, miért nem +1

            # Egy ideiglenes fájlt csinálunk
            TEMPFILE=$(mktemp)

            # A paramétert a „vesszőknél fogva” sorokra tördeljük (awk), az elején levő felesleges szóközöket töröljük (sed) és a TEMPFILE-ba írjuk
            echo $* | awk -F „,” {‘for (i=1;i $TEMPFILE

            # A rekurzív függvénykém
            # Hívása: Permutacio hanyadik_szint eddig_generált_karakter_sor
            function Permutacio () {

                    # Lokális változók…
                    local level
                    local CUR_ROW
                    local i

                    # Az első paramétert eltároljuk, majd őt „kilökjük” (shift), hogy ne zavarjon bele a generált szövegbe
                    level=$1
                    shift

                    # Ha elértük a „bűvös” szintet, akkor az eddig generált karaktersort kiírjuk, és nem rekurvulunk tovább
                    if [ $level -eq $FIELD_NR ]; then
                            echo $*
                            break
                    fi

                    # A level sorszámú („leveledik” 😉 ) sort kiszedjük a fájlból (sed)
                    CUR_ROW=$(sed -n „${level}p” $TEMPFILE)
                    # A level-t eggyel növeljük – bár szerintem ezt a megjegyzést nem is kellett volna ideírni 🙂
                    level=$((level+1))

                    # Az aktuális sor szóközökkel elválasztott szavain szalad végig az i változó
                    for i in $CUR_ROW ; do
                            # Rekurzió, a már megnövelt level-lel, az eddig kapott karaktersor ($*) kibővítve az aktuális „szóval” ($i)
                            Permutacio $level $* $i
                    done
            }

            # Rekurzió elkezdése level=1-gyel és üres sorozattal
            Permutacio 1

            # Szerintem az uccsó sor nem szorul magyarázatra
            rm $TEMPFILE

            Próbáltam én debuggolni (különféle echo-üzik), de mintha az történne, hogy a legutolsó szintű for-cikluson nem halad végig, csak az első elemre hajtja végre a ciklusmagot…

            #2126971
            uzsolt
            Felhasználó

              Hopp, meg is van!
              Azt hittem, hogy a break „csak” a függvényből lép ki. Ezt meg is teszi, de az épp aktuálisan futó for (az előző rekurzió) is megszakad. Ezért a következő a helyes:

              Code:
              #!/bin/bash

              if [ $# -eq 0 ]; then exit ; fi

              FIELD_NR=$(echo $* | grep -o „,” | tr -d „n” | wc -m)
              FIELD_NR=$((FIELD_NR + 2))

              TEMPFILE=$(mktemp)

              echo $* | awk -F „,” {‘for (i=1;i $TEMPFILE

              function Permutacio () {

                      local level
                      local CUR_ROW
                      local i

                      level=$1
                      shift

                      if [ $level -eq $FIELD_NR ]; then
                              echo $*
                      else

                              CUR_ROW=$(sed -n „${level}p” $TEMPFILE)
                              level=$((level+1))

                              for i in ${CUR_ROW} ; do
                                      Permutacio $level $* $i
                              done
                      fi
              }

              Permutacio 1

              rm $TEMPFILE

              És a szám is stimmel:

              Code:
              $ ./perm 1 2 3 , a b c , x y z | wc -l
              27

              (persze a permutációk is megfelelőek, csak 27 sort nem írok még ide)

              #2126972
              uzsolt
              Felhasználó

                Hopp, meg is van!
                Azt hittem, hogy a break „csak” a függvényből lép ki. Ezt meg is teszi, de az épp aktuálisan futó for (az előző rekurzió) is megszakad. Ezért a következő a helyes:

                Code:
                #!/bin/bash

                if [ $# -eq 0 ]; then exit ; fi

                FIELD_NR=$(echo $* | grep -o „,” | tr -d „n” | wc -m)
                FIELD_NR=$((FIELD_NR + 2))

                TEMPFILE=$(mktemp)

                echo $* | awk -F „,” {‘for (i=1;i $TEMPFILE

                function Permutacio () {

                        local level
                        local CUR_ROW
                        local i

                        level=$1
                        shift

                        if [ $level -eq $FIELD_NR ]; then
                                echo $*
                        else

                                CUR_ROW=$(sed -n „${level}p” $TEMPFILE)
                                level=$((level+1))

                                for i in ${CUR_ROW} ; do
                                        Permutacio $level $* $i
                                done
                        fi
                }

                Permutacio 1

                rm $TEMPFILE

                És a szám is stimmel:

                Code:
                $ ./perm 1 2 3 , a b c , x y z | wc -l
                27

                (persze a permutációk is megfelelőek, csak 27 sort nem írok még ide)

                #1886878
                csaba
                Felhasználó

                  Szóval a következővel fordulnék a nagyérdeműhöz: hogy-hogy nem, egy olyan dologra lenne szükségem, ami (bizonyos értelemben) permutációkat ír ki.
                  Egész konkrétan:

                  Code:
                  a b c
                  x y z
                  1 2 3

                  kupacokból mindent mindennel írjon ki, tehát az első karakter az első sorból, a második karakter a második sorból, a harmadik a harmadikból, stb. származzon.
                  Neki is estem, gondoltam paraméterként átadom, és a „sorokat” vesszővel választom el, ebben az esetben az átadott paraméterlista:

                  Code:
                  a b c , x y z , 1 2 3

                  Nyilván a legkézenfekvőbb megoldás a rekurzió, de valahogy egy apró gikszer csak van a progiban. Először is a progi:

                  Code:
                  #!/bin/bash

                  if [ $# -eq 0 ]; then exit ; fi

                  FIELD_NR=$(echo $* | grep -o „,” | tr -d „n” | wc -m)
                  FIELD_NR=$((FIELD_NR + 2))

                  TEMPFILE=$(mktemp)

                  echo $* | awk -F „,” {‘for (i=1;i $TEMPFILE

                  function Permutacio () {

                          local level
                          local CUR_ROW
                          local i

                          level=$1
                          shift

                          if [ $level -eq $FIELD_NR ]; then
                                  echo $*
                                  break
                          fi

                          CUR_ROW=$(sed -n „${level}p” $TEMPFILE)
                          level=$((level+1))

                          for i in $CUR_ROW ; do
                                  Permutacio $level $* $i
                          done
                  }

                  Permutacio 1

                  rm $TEMPFILE

                  Szóval a működése:

                  $ ./perm a b c , x y z , 1 2 3
                  a x 1
                  a y 1
                  a z 1
                  b x 1
                  b y 1
                  b z 1
                  c x 1
                  c y 1
                  c z 1
                  # Tehát a harmadik csoporton nem megy végig
                  $ ./perm a b c , x y z , 1 2 3 , szilva
                  a x 1 szilva
                  a x 2 szilva
                  a x 3 szilva
                  a y 1 szilva
                  a y 2 szilva
                  a y 3 szilva
                  a z 1 szilva
                  a z 2 szilva
                  a z 3 szilva
                  b x 1 szilva
                  b x 2 szilva
                  b x 3 szilva
                  b y 1 szilva
                  b y 2 szilva
                  b y 3 szilva
                  b z 1 szilva
                  b z 2 szilva
                  b z 3 szilva
                  c x 1 szilva
                  c x 2 szilva
                  c x 3 szilva
                  c y 1 szilva
                  c y 2 szilva
                  c y 3 szilva
                  c z 1 szilva
                  c z 2 szilva
                  c z 3 szilva
                  $ ./perm a b c , x y z , 1 2 3 , szilva | wc -l
                  27
                  # Tehát a permutációk száma stimmel

                  Tehát ilyen hekkeléssel tudom csak a jó működésre rábírni. Persze utána törlöm a végéről a szilva szót, de azért mégis, hol a hiba? Esetleg egy elegánsabb megoldás? (lehetőleg bash-ban, csak a móka kedvéért)

                7 bejegyzés megtekintése - 1-7 / 7
                • Be kell jelentkezni a hozzászóláshoz.