Reputation: 43
I have table like this. In real life it will be have more than 1000 rows.
Client | Group -------------- Merry | A Merry | C Susan | B Mike | C Susan | A Joe | A Tom | B Tom | C
And I have list of all clients which is filled from Google Form. I want to fill Group column with groups of every client using only arrayformula in the first row. My desired output is this:
Name | Groups ---------------- Joe | A Tom | B, C Mike | C Merry | A, C Susan | A, B Peter |
My best result yet is this:
Name | Groups | | | | | | | | ---------------------------------------------- Joe | | | | | | A | | | Tom | | | | | | | B | C | Mike | | | | C | | | | | Merry | A | C | | | | | | | Susan | | | B | | A | | | | Peter | | | | | | | | |
Looks like it does what I want but I can't join all these columns into one. Formula is:
=ArrayFormula(IF(name<>"";IF(name=TRANSPOSE(FILTER(client;LEN(client)));TRANSPOSE(FILTER(group;LEN(group))););))
I used "name", "client" and "group" as named ranges according to column headers.
Sample sheet is here (view only): https://docs.google.com/spreadsheets/d/1VFnmyDTQhlCaANAvkzLgzKRKchPsGzFn4hDZYOoJF_M/edit?usp=sharing
Upvotes: 4
Views: 4466
Reputation: 121
Instead of the workaround hacks I implemented a simple joinMatching(matches, values, texts, [sep])
function in Google Apps Script.
In your case it would be just =joinMatching(GroupColumn, ClientColumn, NameColumn, ", ")
.
Source:
// Google Apps Script to join texts in a range where values in second range equal to the provided match value
// Solves the need for `arrayformula(join(',', filter()))`, which does not work in Google Sheets
// Instead you can pass a range of match values and get a range of joined texts back
const identity = data => data
const onRange = (data, fn, args, combine = identity) =>
Array.isArray(data)
? combine(data.map(value => onRange(value, fn, args)))
: fn(data, ...(args || []))
const _joinMatching = (match, values, texts, sep = '\n') => {
const columns = texts[0]?.length
if (!columns) return ''
const row = i => Math.floor(i / columns)
const col = i => i % columns
const value = i => values[row(i)][col(i)]
return (
// JSON.stringify(match) +
texts
.flat()
// .map((t, i) => `[${row(i)}:${col(i)}] ${t} (${JSON.stringify(value(i))})`)
.filter((_, i) => value(i) === match)
.join(sep)
)
}
const joinMatching = (matches, values, texts, sep) =>
onRange(matches, _joinMatching, [values, texts, sep])```
Upvotes: 0
Reputation: 27302
In addition to Rubén's solution, also try
=arrayformula( regexreplace( { unique(A3:A), trim( transpose( query( if( ( transpose(unique(A3:A)) = A3:A ) * len(A3:A), B3:B & ",", ), "select *", 50000) ) ) }, ",$", "" ) )
Note: depending on you locale, you may have to use this formula instead:
=arrayformula( regexreplace( { unique(A3:A)\ trim( transpose( query( if( ( transpose(unique(A3:A)) = A3:A ) * len(A3:A); B3:B & ","; ); "select *"; 50000) ) ) }; ",$"; "" ) )
Upvotes: 3
Reputation: 38435
Considering that the "best result" is on H3:O8
on the linked spreadsheet at this time.
The following formula returns the desired results:
=ArrayFormula(substitute(transpose(trim(query(transpose(H3:O8);"select *";ROWS(A:A))));" ";","))
Explanation
QUERY concatenates the rows values separating them by a space character. The above formula use this feature to concatenate the result got so far by the OP, then TRIM is used to remove the extra spaces and SUBSTITUTE to replace the remaining spaces by a comma.
Upvotes: 2