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
Vektor erstellen
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.
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
Code: Alles auswählen
>>> ''.join(d=="1"and"0001000"or d for d in "000010000010000")
'000000010000000000010000000'
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.
@derdon: Das ist keine Lösung für die Aufgabe.
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.Python_Neuling hat geschrieben:Es wäre prima, wenn jemand eines Lösungsansatz parat hätte
- 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?
Code: Alles auswählen
1
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Bei meinem schnell hingeknallten Code passieren damit gar schröckliche Dinge.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?Code: Alles auswählen
1
- 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
assert encoding_kapiert
Da zu den Randfällen nichts gesagt wurde, traue ich mich mal folgende Lösung in Assembler für den C64 zu präsentieren:
Testlauf:
Der Randfall mit dem der Code nicht klar kommt, ist wenn innerhalb der ersten drei Zeichen schon eine "1" steht.
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
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.
Ein Versuch in C (schmerzhaft wie immer):
(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. )
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;
}
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;
}
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:
`ptr1` dient als Pointer auf/in den `vector`, `y` als Offset zu `ptr1` und das `n` aus der C-Funktion ist das X-Register.
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
Nunja, hier auch nochmal eine etwas veränderte Version meines C-Beispiels oben, auch wenn das immer noch etwas umständlich sein mag:
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?
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;
}
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?
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]
Das ist ein bekanntes Problem mit dem Codehighlighting.problembär hat geschrieben:Edit: [\code=c] scheint im Beitrag statt "&&" "&&" zu liefern?
Das Leben ist wie ein Tennisball.
@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:
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