DataviewJS : I'd like to concatenate two columns into one column

Things I have tried

name:: Tom
lunch:: Pizza
location:: 211

name:: John
lunch:: Sandwich
location:: 309

name:: Sara
lunch:: Fish Burger
location:: 407

// utility function
let transpose = m => m[0].map((x,i) => m.map(x => x[i]));

// Variable for storing results to show
let all_results = []

let files = dv.pages("#lunch").groupBy(p => p.file).filter(g => g.rows.name.length);

// For each file, process the found data
for (let group of files) {
	let p = group.rows

	let names = p.name;
	let lunches = p.lunch;
	let locations = p.location;
		
	let result = transpose([ names, lunches, locations ])

	all_results.push(...result)
}

dv.table([ "Name", "Lunch", "Location" ], all_results)

With the above data and dataviewjs code,

I can get the table like this

Name Lunch Location
Tom Pizza 211
John Sandwich 309
Sara Fish Burger 407

What I’m trying to do

I’d like to change the table like this without changing the data inline YAML format.

Name Lunch
Tom
211
Pizza
John
309
Sandwich
Sara
407
Fish Burger

I found that there is a function for concatenating two strings

concat(other: Iterable<T>): DataArray<T>;

https://blacksmithgu.github.io/obsidian-dataview/api/data-array/

But, I can’t figure out how to use it for my case.

It would be great if someone can give me a hint.
Thank you in advance.

Unrelated to this question: Your transpose utility looks really interesting! Any chance you could explain how it works?

To answer your question: There are several ways to do this. Something that is pretty common in dataviewjs is to call map on your final results before displaying to a table/list. String concat in Javascript can be written with the + sign.
New last line might be:
dv.table([ "Name/Loc", "Lunch" ], all_results.map(r => [ r[0] + "\n" + r[2], r[1] ]));

1 Like

You saved my life! :smiley:

Your codes work like a charm. Thank you very much.

Regarding the transpose utility(?),
I don’t know exactly what it means.
I just get the codes from

I hope you can get some idea about transpose from there.

1 Like

One more question.
Sometimes, location field has no data.

In that case, it looks like r[2] gives ‘null’ as an output.

Is there any method to change those ‘null’ output as something like a blank character?

I tried to change "Render Null As’ from the “Dataview” option.
But, nothing chaged.

1 Like

Good question! Yes I think the “Render null as” option only is used when the whole table cell is null, and since you are combining with the name and a “\n” (line break) that will not ever be the case.

This is kind of ugly code but if you replace r[2] in my line above with (r[2] ? r[2] : " ") null should be replaced with a space (change the space to anything you want by changing what is between the quotes). This uses the Javascript shortcut that null is a “false-y” value and non-null things are “truthy” by asking whether r[2] is truthy (aka not null). If yes, just display it (part after the question mark), if no, display a space instead (part after the :).

From tiny screen, apologies for typos.

1 Like

Following your kind answer,
a lot of ugly “null” disappears from my screen.

Thank you again.

1 Like

I have another question.

Along with my original code & examples,
I’d like to make 26 different pages which contains the names which starts with 26 alpahbet.

I found that

filter(["yes", "no", "yas"], (x) => startswith(x, "y")) = ["yes", "yas"]

from Functions - Dataview.

and, I guess that this function might be what I can apply to my example.

Can you help me once again?

I tried something like this.
result = result.filter(x=>x[0] && x[0].contains("T"))

But, it is not that so good because sometimes there are some names which includes “T” in the middle of their names.

That Functions page is exactly the right page to be looking! I think startswith might be useful to you here. You might want to check both upper and lowercase versions of each letter, depending on your use case.
Is this 26 pages still for the lunch example by the way? If not, it might be helpful to open a second thread explaining what you are doing, because writing out 26 versions of anything sounds tedious and maybe there is a better solution.

This question was also for the lunch example.
Because I have a lot of names, it got a little slow in listing and sorting all of them in one page.
So, I wanted to divide them into 26 pages which starts with the first letter of their names.

Even though, I don’t know exactly how the code works, I found the answer for my use.

By inserting

result = result.filter(x=>x[0][0].contains("T"))

just before

all_results.push(...result)

Now, I got the names which starts with “T”. It might not be so effective, but it’s O.K for my purpose.

Thank you again.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.