Vektor erstellen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Python_Neuling
User
Beiträge: 1
Registriert: Dienstag 22. November 2011, 18:30

Hallo,
da ich mich mit Python noch nicht gut auskenne, verzweifle ich seit Tagen an folgender Aufgabe:
Ich soll einen Vektor (V1) mit Nullen und Einsen erstellen. V1 =
000010000010000. Nun soll ich aus V1 einen Vektor (V2) erstellen, der
folgende Eigenschaft hat: Jedes mal, wenn in V1 eine 1 ist, sollen vor
und hinter der 1 drei weitere 1en gesetzt werden. So dass V2 dann so
aussieht:

V1 = 0000 1 00000 1 0000 bzw. False False False False True usw.

[mein Script, was aus V1 V2 macht]

V2 = 0111 1 11111 1 1110 bzw. False True True True True usw.

Es wäre prima, wenn jemand eines Lösungsansatz parat hätte :)
deets

So laeuft das hier nicht. Du sollst deine Hausaufgaben schon selbst machen. Wir helfen gerne - aber nur dann, wenn wir sehen, dass du dich selbst bemuehst, indem du deinen bestehenden Code hier postest (python-tags nicht vergessen...), zusammen mit konkreten Fragen und/oder Fehlerbeschreibungen.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Wenn du die Lösung deinem Lehrer zeigst, wird er eh nicht glauben, dass es von dir kommt, weil du niemals so schrecklichen Code schreiben würdest :P

Code: Alles auswählen

>>> ''.join(d=="1"and"0001000"or d for d in "000010000010000")
'000000010000000000010000000'
BlackJack

Die Hausaufgabe haben noch andere. Und einer davon hat sie vor ein paar Tagen hier erst von jemandem gelöst bekommen.

@derdon: Das ist keine Lösung für die Aufgabe.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Python_Neuling hat geschrieben:Es wäre prima, wenn jemand eines Lösungsansatz parat hätte :)
Lösungsansatz: Du könntest die Positionen ermitteln die eine '1' enthalten und dann anschließend jeweils den Teil davor und dahinter mit '111' überschreiben.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

BlackJack: Umso besser! Hab's auch gerade gemerkt, bei meinem Code wird ja nicht überschrieben.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Interessant wäre noch zu wissen, ob V1 immer so lang ist oder er auch kürzer sein kann. Was passiert z.B. hiermit?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Hyperion hat geschrieben:Interessant wäre noch zu wissen, ob V1 immer so lang ist oder er auch kürzer sein kann. Was passiert z.B. hiermit?
Bei meinem schnell hingeknallten Code passieren damit gar schröckliche Dinge. :mrgreen:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich habe eine Lösung mittels `defaultdict` gefunden - da spielt dann ein "Übertreten" der Grenzen keine Rolle mehr, zudem erspart man sich das Slicing.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

Da zu den Randfällen nichts gesagt wurde, traue ich mich mal folgende Lösung in Assembler für den C64 zu präsentieren:

Code: Alles auswählen

        !to "test.prg", cbm
        
        ptr     = $fa
        
        chrout  = $ffd2
        strout  = $ab1e
        
        * = $c000

start   lda #<vector
        ldy #>vector
        sta ptr
        sty ptr+1
        jsr strout
        lda #13
        jsr chrout
        
        ldx #0
loop    ldy #3
        lda (ptr),y
        beq done
        cmp #"1"
        bne +
        ldx #7
+       cpx #0
        beq ++
        lda #"1"
        dex
++      ldy #0
        sta (ptr),y
        inc ptr
        bne loop
        inc ptr+1
        bne loop

done    lda #<vector
        ldy #>vector
        jsr strout
        lda #13
        jmp chrout

vector  !pet "00001001000000001000000", 0
Testlauf:

Code: Alles auswählen

       JIFFYDOS V6.01 (C)1989 CMD

 C-64 BASIC V2   38911 BASIC BYTES FREE

   CYBERPUNX RETRO REPLAY 64KB - 3.8P

READY.
LOAD"TEST.PRG",8,1

SEARCHING FOR TEST.PRG
LOADING $C000 $C055
READY.
SYS49152
00001001000000001000000
01111111111001111111000

READY.
Der Randfall mit dem der Code nicht klar kommt, ist wenn innerhalb der ersten drei Zeichen schon eine "1" steht.
problembär

Ein Versuch in C (schmerzhaft wie immer):

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* convvec.c - Convert Vector, compile with: 
   gcc -Wall -Wextra -ansi -pedantic convvec.c -o convvec */

char *convertvector(char *vector, int width);

int main() {
    char vector[16] = "000010000010000";
    puts(vector);
    puts(convertvector(vector, 3));
    return 0;
}

char *convertvector(char *vector, int width) {
    int i;
    int u;
    int ones[15];
    int oneindex;
    int tochange[15];
    int tochangeindex;
    int vectorlength;
    char *vectorp;
    oneindex = 0;
    tochangeindex = 0;
    vectorlength = strlen(vector);
    for(i = 0; i < vectorlength; i ++) {
        if(vector[i] == '1') {
            ones[oneindex] = i;
            oneindex++;
        }
    }
    for(i = 0; i < oneindex; i++) {
        for(u = 1; u <= width; u++) {
            tochange[tochangeindex] = ones[i] + u;
            tochangeindex++;
            tochange[tochangeindex] = ones[i] - u;
            tochangeindex++;
        }
    }
    for(i = 0; i < tochangeindex; i++) {
        vectorp = vector;
        if(tochange[i] >= 0) {
            vectorp += tochange[i];
            *vectorp = '1';
        }
    }
    return vector;
}
(Kann sein, daß man "vector" in main() besser als Zeiger auf char mit malloc() anlegen sollte; bin dabei immer etwas unsicher. Glücklicherweise nimmt Python einem solche Fragen ab. :D)
BlackJack

Eine C-Lösung die mit weniger lokalen Variablen und einem einzigen Durchlauf des Vektors auskommt *und* die Randfälle berücksichtigt!

Code: Alles auswählen

#include <iso646.h>
#include <stdio.h>

#define HALF_WIDTH      3

void set_ones(char *vector)
{
    char c;
    unsigned int i, n = 0;
    
    for (i = 0; i < HALF_WIDTH and (c = vector[i]); ++i) {
        if (c == '1') n = HALF_WIDTH + i + 1;
    }
    for (i = 0; (c = vector[i + HALF_WIDTH]); ++i) {
        if (c == '1') n = HALF_WIDTH * 2 + 1;
        if (n) {
            vector[i] = '1';
            --n;
        }
    }
    while (n and vector[i]) {
        vector[i++] = '1';
        --n;
    }
}

int main(void)
{
    char vector[] = "00001001000000001000000";
    puts(vector);
    set_ones(vector);
    puts(vector);
    return 0;
}
problembär

@BlackJack: Schöner Code!
BlackJack

Hier noch einmal eine überarbeitete Assemblerfassung. Die alte war ja sozusagen die mittlere Schleife aus der C-Funktion. Die beiden anderen Schleifen sind jetzt dazu gekommen:

Code: Alles auswählen

        .importzp   ptr1
        .export     _set_ones

        HALF_WIDTH = 3
; 
; void __fastcall__ set_ones(char *vector);
; 
.proc _set_ones
.code
        sta ptr1
        stx ptr1+1
        
        ldx #0
        ldy #$ff
        bne L2
loop1:  lda (ptr1),y
        beq loop2
        cmp #'1'
        bne L2
        tya
        clc
        adc #HALF_WIDTH + 1
        tax
L2:     iny
        cpy #HALF_WIDTH
        bne loop1

loop2:  ldy #HALF_WIDTH
        lda (ptr1),y
        beq endloop2
        cmp #'1'
        bne @skip1
        ldx #HALF_WIDTH * 2 + 1
@skip1: cpx #0
        beq @skip2
        dex
        lda #'1'
        ldy #0
        sta (ptr1),y
@skip2: inc ptr1
        bne loop2
        inc ptr1+1
        bne loop2
endloop2:

        ldy #0
loop3:  dex
        bmi endloop3
        lda (ptr1),y
        beq endloop3
        lda #'1'
        sta (ptr1),y
        iny
        bne loop3
endloop3:
        rts
.endproc
`ptr1` dient als Pointer auf/in den `vector`, `y` als Offset zu `ptr1` und das `n` aus der C-Funktion ist das X-Register.
problembär

Nunja, hier auch nochmal eine etwas veränderte Version meines C-Beispiels oben, auch wenn das immer noch etwas umständlich sein mag:

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* convvec.c - Convert Vector, compile with:
   gcc -Wall -Wextra -ansi -pedantic convvec.c -o convvec */

char *convertvector(char *vector, int width);

int main() {
    /* char vector[] = "000010000010000"; */
    char vector[] = "00001001000000001000000";
    puts(vector);
    puts(convertvector(vector, 3));
    return 0;
}

char *convertvector(char *vector, int width) {
    int i;
    int u;
    int vectorlength = strlen(vector);
    int *ones = malloc(vectorlength - 1);
    int oneindex;
    int *tochange = malloc(vectorlength - 1);
    int tochangeindex;
    oneindex = 0;
    tochangeindex = 0;
    for(i = 0; i < vectorlength; i ++) {
        if(vector[i] == '1') {
            ones[oneindex] = i;
            oneindex++;
        }
    }
    for(i = 0; i < oneindex; i++) {
        for(u = 1; u <= width; u++) {
            tochange[tochangeindex] = ones[i] + u;
            tochangeindex++;
            tochange[tochangeindex] = ones[i] - u;
            tochangeindex++;
        }
    }
    for(i = 0; i < tochangeindex; i++) {
        if(tochange[i] >= 0 && i < vectorlength) {
            vector[tochange[i]] = '1';
        }
    }
    return vector;
}
Der Zeiger "*vectorp" ist weg. Wenn ich einen C-String als Zeiger auf char hatte und den ändern wollte, hab' ich sonst einen zweiten Zeiger auf die Anfangsadresse gesetzt und bin mit diesem an die Stellen hin- und hergesprungen, die ich ändern wollte. So auch mit diesem "*vectorp". Grund für den zweiten Zeiger war, das man mit dem ersten immer noch die Anfangsadresse gespeichert hatte, die man ja brauchte, etwa um den String auszugeben. Na ja, das ist alles gar nicht nötig: Man kann C-Strings ja auch gleichzeitig als Arrays betrachten und Zeichen darin über z.B. vector[3] usw. ändern. Wieder was gelernt.
Die Dimensionierung der Arrays "ones" und "tochange" mit festen Zahlen (hier: 15) war natürlich nicht optimal. Jetzt also eine dynamische Dimensionierung mit malloc(). Hab' so noch nie ein int-Array dimensioniert. Scheint zu gehen ...
Über die Randfälle hatte ich mir zuvor auch schon Gedanken gemacht. Bei der Aufgabenstellung ist mir nicht klar, wie bei denen verfahren werden soll. Bei mir wird ja in "tochange" gespeichert, welche Stellen von "vector" geändert werden sollen. Hab' halt eine Bedingung eingebaut, daß nur dann die Änderung wirklich durchgeführt werden soll, wenn der in "tochange" gespeicherte Wert innerhalb der Länge von "vector" liegt. Sonst wird eben gar nichts gemacht. Weiß nicht, ob das der Aufgabenstellung entspricht.
Hab' jedenfalls dabei wieder ein, zwei Schritte in C gelernt. Bin da ja (wie man sieht) noch recht am Anfang. War also ganz hilfreich, die Hausaufgabe. Für mich jedenfalls. ;)

Edit: [\code=c] scheint im Beitrag statt "&&" "&&" zu liefern?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das schreit doch schon fast nach dem Einsatz von zip:

Code: Alles auswählen

>>> example = [0,0,0,0,1,0,0,0,0,0,1,0,0,0,0]
>>> size = 3
>>> map(int, map(any, zip(*[([0]*size+example+[0]*size)[i:] for i in range(2*size+1)])))
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
problembär hat geschrieben:Edit: [\code=c] scheint im Beitrag statt "&&" "&&" zu liefern?
Das ist ein bekanntes Problem mit dem Codehighlighting.
Das Leben ist wie ein Tennisball.
BlackJack

@problembär: Du forderst mit `malloc()` mit an Sicherheit grenzender Wahrscheinlichkeit nicht genug Speicher an. Das funktioniert also nur solange nicht zu viele '1'en in `vector` sind. Wenn Du Speicher für `n` ``int``\s haben möchtest, dann musst Du ``n * sizeof(int)`` Bytes anfordern. Die ``- 1`` ist auch falsch. `ones` muss mindestens die Länge von `vector` haben, und `tochange` muss die Länge von `vector` plus zwei mal `width` haben um für den Fall gewappnet zu sein, dass der `vector` tatsächlich nur aus '1'en besteht.

Am Ende der Funktion solltest Du den dynamisch angeforderten Speicher auch wieder frei geben.

Wegen dem kaputten Syntax-Highlighter hatte ich ``iso646.h`` eingebunden, damit ich ``and`` anstelle von ``&&`` schreiben konnte. Das mache ich normalerweise nicht.

Edit: Man kann das auf dem C64 natürlich auch ganz traditionell in BASIC lösen:

Code: Alles auswählen

   10 HW=3:V$="00001001000000001000000":LV=LEN(V$):PRINT V$
   20 DIM V$(LV):FOR I=0 TO LV:V$(I)=MID$(V$,I+1,1):NEXT
   30 N=0:FOR I=0 TO HW:IF V$(I)="1" THEN N=HW+1+I
   40 NEXT
   50 FOR I=0 TO LV-HW:IF V$(I+HW)="1" THEN N=HW*2+1
   60 IF N>0 THEN V$(I)="1":N=N-1
   70 NEXT
   80 IF N=0 OR I=LV THEN 100
   90 V$(I)="1":I=I+1:N=N-1:GOTO 80
  100 FOR I=0 TO LV:PRINT V$(I);:NEXT:PRINT
Antworten