javascript map() - auf bestimmte Elemente von value zugreifen
ebody
- javascript
Hallo,
ich möchte auf bestimmte Elemente von value zugreifen:
const items = movies.filter(value => value.row === 1).map(value => value[0]);
value[0] gibt undefined zurück. Kann man in einer anderen Schreibweise auf das erste, zweite... Element von value zugreifen?
Ziel ist ein neues Array zusammen zu stellen:
// movies[] durchlaufen und dabei nach row filtern
for (i = 0; i < movies.length; i++) {
const items = movies.filter(value => value.row === i).map(value => ({movie:value[0].content,medium:value[1].content}));
}
Zum Hintergrund der Frage:
/**
* movies[] ist eine verkürtze Darstellung eines Google Spreadsheet Arrays
* Die Inhalte aus dem Array sollen in einem neuen Array je Datensatz (row) zusammengefügt werden, um dieses neue Array für verschiedene Funktionen besser/einfacher nutzen zu können.
*/
const movies = [
{
content: 'Batman Begins',
col: 1,
row: 1
},
{
content: 'Blu Ray',
col: 2,
row: 1
},
{
content: 'The Dark Knight',
col: 1,
row: 2
},
{
content: 'Blu Ray',
col: 2,
row: 2
}
];
// movies[] durchlaufen und dabei nach row filtern
for (i = 0; i < movies.length; i++) {
// const items = movies.filter(value => value.row === i).map(value => value);
const items = movies.filter(value => value.row === i).map(value => value[0]); // [undefined, undefined]
// const items = movies.filter(value => value.row === i).map(value => value[0].content); // Cannot read property 'content' of undefined
// const items = movies.filter(value => value.row === 1).map(value => ({movie:value[0].content,medium:value[1].content})); // Cannot read property 'content' of undefined
console.log('items', items);
}
Gruß ebody
Tach!
ich möchte auf bestimmte Elemente von value zugreifen:
Es wäre lesbarer, wenn du sprechende Namen verwendest statt dem generischen "value". In dem Fall wäre "movie" ein guter Name, weil das ein Element des movies-Array darstellt. Das gilt sowohl für filter() als auch für map().
const items = movies.filter(value => value.row === 1).map(value => value[0]);
Und damit würde man sehen, dass movie kein Array ist und der Zugriff auf [0]
nicht sinnvoll ist.
value[0] gibt undefined zurück. Kann man in einer anderen Schreibweise auf das erste, zweite... Element von value zugreifen?
Da stellt sich dann die Frage, was das erste, zweite... Element eines movie sein soll. Oder aber: auf was konkret möchtest du eigentlich zugreifen?
dedlfix.
Hi,
hattest du den kompletten Code gesehen und das Array movies[]? Ich weiß halt nicht genau, was value
alles enthält und wirklich ist. Wenn ich items ausgebe, bekomme ich ein neues Array mit den ersten beiden Elementen aus movies[].
const items = movies.filter(value => value.row === 1).map(value => value);
console.log('items', items);
Daher gehe ich davon aus, das value
genau dieses neue Array ist (ist dem so?) und man auf die Elemente dieses neuen Arrays auch direkt zugreifen kann:
Beispiel:
const items = movies.filter(value => value.row === 1).map(value => value[0]);
console.log('items', items);
Was aber so leider undefined
zurückgibt.
Gruß ebody
Tach!
hattest du den kompletten Code gesehen und das Array movies[]? Ich weiß halt nicht genau, was
value
alles enthält und wirklich ist.
Das ergibt sich aus der Funktionsweise der Methoden Array.filter() und Array.map(). Beiden ist gemein, dass sie ein Array durchlaufen und jeweils ein Element davon an die Callback-Funktion übergeben. Somit ist dein "value" jeweils ein Eintrag aus dem movies-Array, mithin also ein movie.
Wenn ich items ausgebe, bekomme ich ein neues Array mit den ersten beiden Elementen aus movies[].
const items = movies.filter(value => value.row === 1).map(value => value); console.log('items', items);
Daher gehe ich davon aus, das
value
genau dieses neue Array ist (ist dem so?)
Nein. Zunächst einmal hast du da zweimal "value", das eine in der Callback-Funktion von filter() und das zweite in der Callback-Funktion von map(). Ich nehme an, du meinst in dem Satz das zweite "value". Auch das enthält jeweils nur einen Film und nicht das gesamte - nun gefilterte - Array. Um einzelne Elemente eines Arrays gezielt anzusprechen, brauchst du kein .map(), sondern greifst über die Index-Notation zu.
const filteredMovies = movies.filter(movie => movie.row === 1);
console.log('filteredMovies', filteredMovies);
console.log('erstes Element', filteredMovies[0]);
console.log('zweites Element', filteredMovies[1]);
und man auf die Elemente dieses neuen Arrays auch direkt zugreifen kann:
Ja, aber ohne .map().
Beispiel:
const items = movies.filter(value => value.row === 1).map(value => value[0]); console.log('items', items);
Was aber so leider
undefined
zurückgibt.
Ein Debugger ist ein wichtiges Werkzeug zum Erkenntnisgewinn beim Programieren. Die Browser haben einen eingebaut, man muss ihn nur nutzen. Zur Not gibt es das von dir schon verwendete console.log(), mit dem du auch sehen könntest, was "value" wirklich ist: .map(value => console.log(value))
.
dedlfix.
Hallo ebody,
Ich weiß halt nicht genau, was value alles enthält
Anhand deines Beispiels: Doch. Du weißt genau, dass das ein Objekt mit drei Eigenschaften ist: content, row und col.
Die filter-Methode kopiert diejenigen Einträge eines Arrays, für die die Callbackfunktion true
liefert. Bei Dir ist der Callback (wenn ich Dedlfix' Anregung mit dem sprechenderen Namen aufgreife) dieser:
movie => movie.row === 1
D.h. das Ergebnis des filter-Aufrufs ist ein Array mit den Filmen Batman Begins und Blu Ray. Blauer Rochen? Nie gehört, ist der gut?
Achso, das sind ja gar nicht alles Filme. Es sind Spreadsheet-Zellen und "Blu Ray" ist das Medium, auf dem "Batman Begins" vorliegt.
Dann nenn das verd***te Array doch bitte cells
und nicht movies
!!1!!elf!1
Nach dem Filter-Aufruf hast Du dieses Array:
[
{
content: 'Batman Begins',
col: 1,
row: 1
},
{
content: 'Blu Ray',
col: 2,
row: 1
}
]
und der map-Aufruf wird nun wiederum auf jeden einzelnen Eintrag darin angewendet. Zuerst auf die Namensspalte (col:1), dann auf die Medienspalte (col:2).
Aber ich glaube, das willst Du nicht. Du möchtest das Filterergebnis zu einem einzigen Objekt zusammensetzen. Dafür ist map ungeeignet. Mit map wandelt man einen Array-Eintrag in einen neuen Wert um.
Du möchtest statt dessen mehrere Array-Einträge zu einem Objekt aggregieren:
{
movie: "Batman Begins", /* content für col:1 */
medium: "Blu Ray" /* content für col:2 */
}
und vermutlich hast Du in der Realität noch ein paar Spalten mehr.
Deine Steuerschleife am Ende ist dann auch unpassend, denn
for (i = 0; i < movies.length; i++) {
}
würde ja einen Durchlauf pro Spreadsheet-ZELLE und nicht pro Spreadsheet-ZEILE machen.
Man kann das Problem mit der filter-Methode lösen, aber dann
Ergebnis:
[
{
movie: "Batman Begins",
medium: "Blu Ray"
},
{
movie: "The Dark Night",
medium: "Blu Moray"
}
]
Zum Verteilen kannst Du eine Hilfsfunktion bauen, die Dir aus einem Array von Zellen den Wert der Zelle mit einer bestimmten Spaltennummer heraussucht.
let movie = {
movie: getCellValue(cellsForOneMovie, 1),
medium: getCellValue(cellsForOneMovie, 2)
}
function getCellValue(cells, col) {
// das kriegst Du selber hin
}
Wenn Du viele Zellen für einen Film hast, ist das lästig. Man könnte auch ein Array aufbauen, das den Spaltennummern Namen zuordnet. Ein Dummy-Eintrag vorneweg, weil JS-Arrays ja mit 0 beginnen.
const columnNames = [ '', 'movie', 'medium', 'erschienen', 'regisseur', 'prodKosten' ],
maxColumn = columnNames.length - 1;
let movie = { };
for (let cell of cellsForOneMovie) { // for..of nicht im Internet Explorer!
if (cell.col >= 1 && cell.col <= maxColumn) {
colName = columnNames[cell.col];
movie[colName] = cell.content;
}
}
Für diesen Weg brauchst Du kein Durchsuchen der Zellen nach Spaltennummern, du ordnest über columnNames direkt die Spaltennummern einem Propertynamen zu.
Rolf
Hallo Rolf,
Nachtrag: Wenn die Zellen zumindest nach row sortiert vorliegen (sortiert nach col ist nicht nötig) kann man auf die Filterei auch verzichten und mit einem Gruppenwechsel arbeiten.
Das ist nur unwesentlich komplizierter (wenn man die Idee gerafft hat) und deutlich fixer, weil nicht für jeden Film das komplette Zellen-Array durchforstet werden muss.
Rolf
Hallo ebody,
vielleicht ist das interessant für dich:
https://www.mediaevent.de/javascript/array-multidimensional.html
Denn bei den Verschachtelungen und Neustrukturierungen, gibts zwar viele Wege, doch meist multidimensional. Daher der Link mal als Anregung.
Gruss
Henry