My intention is to convert a single line of data into rows consist of a specific number of columns in Google Sheets.
For example, starting with the raw data:
A
B
C
D
E
F
1
id1
attr1-1
attr2-1
id2
attr2-1
attr2-2
And the expected result is:
(by dividing columns by three)
A
B
C
1
id1
attr1-1
attr1-2
2
id2
attr2-1
attr2-2
I already know that it's possible a bit manually, like:
=ARRAYFORMULA({A1:C1;D1:F1})
But I have to start over with it every time the target range is moved OR the subset size needs to be changed (in the case above it was three)!
So I guess there will be a much more graceful way (i.e. formula does not require manual update) to do the same thing and suspect ARRAYFORMULA() is the key.
Any help will be appreciated!
I added a new sheet ("Erik Help") where I reduced your manually entered parameters from two to one (leaving only # of columns to be entered in A2).
The formula that reshapes the grid:
=ArrayFormula(IFERROR(VLOOKUP(SEQUENCE(ROUNDUP(COUNTA(7:7)/A2),A2),{SEQUENCE(COUNTA(7:7),1),FLATTEN(FILTER(7:7,7:7<>""))},2,FALSE)))
SEQUENCE is used to shape the grid according to whatever is entered in A2. Rows would be the count of items in Row 7 divided by the number in A2 (rounded to the nearest whole number); and the columns would just be whatever number is entered in A2.
Example: If there are 11 items in Row 7 and you want 4 columns, ROUNDUP(11/4)=3 rows to the SEQUENCE and your requested 4 columns.
Then, each of those numbers in the grid is VLOOKUP'ed in a virtual array consisting of a vertical SEQUENCE of ordered numbers matching the number of data pieces in Row 7 (in Column 1) and a FLATTENed (vertical) version of the Row-7 data pieces themselves (in Column 2). Matches are filled into the original SEQUENCE grid, while non-matches are left blank by IFERROR
Though it's a bit messy, managed to get it done thanks to SEQUENCE() function anyway.
It constructs a grid by accepting number of rows/columns input, and that was exactly I was looking for.
For reference set up a sheet with the sample data here:
https://docs.google.com/spreadsheets/d/1p972tYlsPvC6nM39qLNjYRZZWGZYsUnGaA7kXyfJ8F4/edit#gid=0
Use a custom formula
Although you already solved this. If you are doing this kind of thing a lot, it could be beneficial to look into Apps Script and custom formulas.
In this case you could use something like:
function transposeSingleRow(range, size) {
// initialize new range
let newRange = []
// initialize counter to keep track
let count = 0;
// start while loop to go through row (range[0])
while (count < range[0].length){
// add a slice of the original range to the new range
newRange.push(
range[0].slice(count, count + size)
);
// increment counter
count += size;
}
return newRange;
}
Which works like this:
The nice thing about the formula here is that you select the range, and then you put in a number to represent its throw, or how many elements make up a complete row. So if instead of 3 attributes you had 4, instead of calling:
=transposeSingleRow(A7:L7, 3)
you could do:
=transposeSingleRow(A7:L7, 4)
Additionally, if you want this conversion to be permanent and not dependent on formula recalculation. Making it in run fully in Apps Script without using formulas would be neccesary.
Reference
Apps Script
Custom Functions
I need to add three cells in excel 2010, for example:
val1 = 1
val2 = 3
val3 = #N/A
sum = 4
As you can see, I need the result to be a number, not #N/A.
I would like #N/A to count as 0.
Thank you!
Try this:
=SUM(IF(ISERROR(A1:A3),0,A1:A3))
Entered as Array Formula by pressing Ctrl+Shft+Enter in Cell A4 assuming your data is in Column A.
Change the address otherwise.
I have solved it myself, but L42 pointed me into the right direction.
In my table, data is located in J2, K2 and L2 and the sum is in M2 where I entered the final formula: =IFERROR(J2;0)+IFERROR(K2;0)+IFERROR(L2;0)
which basically means that I have manually added the 3 cells but checked for errors first, for each cell, with the function iferror and returned 0 if error exists.
Thank you!
I am looking for formula for google spreadsheet
highlight cell if value duplicate in same column
can anyone please assist me for this query?
Try this:
Select the whole column
Click Format
Click Conditional formatting
Click Add another rule (or edit the existing/default one)
Set Format cells if to: Custom formula is
Set value to: =countif(A:A,A1)>1 (or change A to your chosen column)
Set the formatting style.
Ensure the range applies to your column (e.g., A1:A100).
Click Done
Anything written in the A1:A100 cells will be checked, and if there is a duplicate (occurs more than once) then it'll be coloured.
For locales using comma (,) as a decimal separator, the argument separator is most likely a semi-colon (;). That is, try: =countif(A:A;A1)>1, instead.
For multiple columns, use countifs.
While zolley's answer is perfectly right for the question, here's a more general solution for any range, plus explanation:
=COUNTIF($A$1:$C$50, INDIRECT(ADDRESS(ROW(), COLUMN(), 4))) > 1
Please note that in this example I will be using the range A1:C50.
The first parameter ($A$1:$C$50) should be replaced with the range on which you would like to highlight duplicates!
to highlight duplicates:
Select the whole range on which the duplicate marking is wanted.
On the menu: Format > Conditional formatting...
Under Apply to range, select the range to which the rule should be applied.
In Format cells if, select Custom formula is on the dropdown.
In the textbox insert the given formula, adjusting the range to match step (3).
Why does it work?
COUNTIF(range, criterion), will compare every cell in range to the criterion, which is processed similarly to formulas. If no special operators are provided, it will compare every cell in the range with the given cell, and return the number of cells found to be matching the rule (in this case, the comparison). We are using a fixed range (with $ signs) so that we always view the full range.
The second block, INDIRECT(ADDRESS(ROW(), COLUMN(), 4)), will return current cell's content. If this was placed inside the cell, docs will have cried about circular dependency, but in this case, the formula is evaluated as if it was in the cell, without changing it.
ROW() and COLUMN() will return the row number and column number of the given cell respectively. If no parameter is provided, the current cell will be returned (this is 1-based, for example, B3 will return 3 for ROW(), and 2 for COLUMN()).
Then we use: ADDRESS(row, column, [absolute_relative_mode]) to translate the numeric row and column to a cell reference (like B3. Remember, while we are inside the cell's context, we don't know it's address OR content, and we need the content in order to compare with). The third parameter takes care for the formatting, and 4 returns the formatting INDIRECT() likes.
INDIRECT(), will take a cell reference and return its content. In this case, the current cell's content. Then back to the start, COUNTIF() will test every cell in the range against ours, and return the count.
The last step is making our formula return a boolean, by making it a logical expression: COUNTIF(...) > 1. The > 1 is used because we know there's at least one cell identical to ours. That's our cell, which is in the range, and thus will be compared to itself. So to indicate a duplicate, we need to find 2 or more cells matching ours.
Sources:
Docs Editors Help: COUNTIF()
Docs Editors Help: INDIRECT()
Docs Editors Help: ADDRESS()
Docs Editors Help: ROW()
Docs Editors Help: COLUMN()
Answer of #zolley is right. Just adding a Gif and steps for the reference.
Goto menu Format > Conditional formatting..
Find Format cells if..
Add =countif(A:A,A1)>1 in field Custom formula is
Note: Change the letter A with your own column.
From the "Text Contains" dropdown menu select "Custom formula is:", and write: "=countif(A:A, A1) > 1" (without the quotes)
I did exactly as zolley proposed, but there should be done small correction: use "Custom formula is" instead of "Text Contains".
And then conditional rendering will work.
Highlight duplicates (in column C):
=COUNTIF(C:C, C1) > 1
Explanation: The C1 here doesn't refer to the first row in C. Because this formula is evaluated by a conditional format rule, instead, when the formula is checked to see if it applies, the C1 effectively refers to whichever row is currently being evaluated to see if the highlight should be applied. (So it's more like INDIRECT(C &ROW()), if that means anything to you!). Essentially, when evaluating a conditional format formula, anything which refers to row 1 is evaluated against the row that the formula is being run against. (And yes, if you use C2 then you asking the rule to check the status of the row immediately below the one currently being evaluated.)
So this says, count up occurences of whatever is in C1 (the current cell being evaluated) that are in the whole of column C and if there is more than 1 of them (i.e. the value has duplicates) then: apply the highlight (because the formula, overall, evaluates to TRUE).
Highlight the first duplicate only:
=AND(COUNTIF(C:C, C1) > 1, COUNTIF(C$1:C1, C1) = 1)
Explanation: This only highlights if both of the COUNTIFs are TRUE (they appear inside an AND()).
The first term to be evaluated (the COUNTIF(C:C, C1) > 1) is the exact same as in the first example; it's TRUE only if whatever is in C1 has a duplicate. (Remember that C1 effectively refers to the current row being checked to see if it should be highlighted).
The second term (COUNTIF(C$1:C1, C1) = 1) looks similar but it has three crucial differences:
It doesn't search the whole of column C (like the first one does: C:C) but instead it starts the search from the first row: C$1
(the $ forces it to look literally at row 1, not at whichever row is being evaluated).
And then it stops the search at the current row being evaluated C1.
Finally it says = 1.
So, it will only be TRUE if there are no duplicates above the row currently being evaluated (meaning it must be the first of the duplicates).
Combined with that first term (which will only be TRUE if this row has duplicates) this means only the first occurrence will be highlighted.
Highlight the second and onwards duplicates:
=AND(COUNTIF(C:C, C1) > 1, NOT(COUNTIF(C$1:C1, C1) = 1), COUNTIF(C1:C, C1) >= 1)
Explanation: The first expression is the same as always (TRUE if the currently evaluated row is a duplicate at all).
The second term is exactly the same as the last one except it's negated: It has a NOT() around it. So it ignores the first occurence.
Finally the third term picks up duplicates 2, 3 etc. COUNTIF(C1:C, C1) >= 1 starts the search range at the currently evaluated row (the C1 in the C1:C). Then it only evaluates to TRUE (apply highlight) if there is one or more duplicates below this one (and including this one): >= 1 (it must be >= not just > otherwise the last duplicate is ignored).
I tried all the options and none worked.
Only google app scripts helped me.
source : https://ctrlq.org/code/19649-find-duplicate-rows-in-google-sheets
At the top of your document
1.- go to tools > script editor
2.- set the name of your script
3.- paste this code :
function findDuplicates() {
// List the columns you want to check by number (A = 1)
var CHECK_COLUMNS = [1];
// Get the active sheet and info about it
var sourceSheet = SpreadsheetApp.getActiveSheet();
var numRows = sourceSheet.getLastRow();
var numCols = sourceSheet.getLastColumn();
// Create the temporary working sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var newSheet = ss.insertSheet("FindDupes");
// Copy the desired rows to the FindDupes sheet
for (var i = 0; i < CHECK_COLUMNS.length; i++) {
var sourceRange = sourceSheet.getRange(1,CHECK_COLUMNS[i],numRows);
var nextCol = newSheet.getLastColumn() + 1;
sourceRange.copyTo(newSheet.getRange(1,nextCol,numRows));
}
// Find duplicates in the FindDupes sheet and color them in the main sheet
var dupes = false;
var data = newSheet.getDataRange().getValues();
for (i = 1; i < data.length - 1; i++) {
for (j = i+1; j < data.length; j++) {
if (data[i].join() == data[j].join()) {
dupes = true;
sourceSheet.getRange(i+1,1,1,numCols).setBackground("red");
sourceSheet.getRange(j+1,1,1,numCols).setBackground("red");
}
}
}
// Remove the FindDupes temporary sheet
ss.deleteSheet(newSheet);
// Alert the user with the results
if (dupes) {
Browser.msgBox("Possible duplicate(s) found and colored red.");
} else {
Browser.msgBox("No duplicates found.");
}
};
4.- save and run
In less than 3 seconds, my duplicate row was colored. Just copy-past the script.
If you don't know about google apps scripts , this links could be help you:
https://zapier.com/learn/google-sheets/google-apps-script-tutorial/
https://developers.google.com/apps-script/overview
I hope this helps.
I use the following function
=DAYS360(A2, A35)
to calculate the difference between two dates in my column. However, the column is ever expanding and I currently have to manually change 'A35' as I update my spreadsheet.
Is there a way (in Google Sheets) to find the last non-empty cell in this column and then dynamically set that parameter in the above function?
There may be a more eloquent way, but this is the way I came up with:
The function to find the last populated cell in a column is:
=INDEX( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ; ROWS( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ) )
So if you combine it with your current function it would look like this:
=DAYS360(A2,INDEX( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ; ROWS( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ) ))
To find the last non-empty cell you can use INDEX and MATCH functions like this:
=DAYS360(A2; INDEX(A:A; MATCH(99^99;A:A; 1)))
I think this is a little bit faster and easier.
If A2:A contains dates contiguously then INDEX(A2:A,COUNT(A2:A)) will return the last date. The final formula is
=DAYS360(A2,INDEX(A2:A,COUNT(A2:A)))
Although the question is already answered, there is an eloquent way to do it.
Use just the column name to denote last non-empty row of that column.
For example:
If your data is in A1:A100 and you want to be able to add some more data to column A, say it can be A1:A105 or even A1:A1234 later, you can use this range:
A1:A
So to get last non-empty value in a range, we will use 2 functions:
COUNTA
INDEX
The answer is =INDEX(B3:B,COUNTA(B3:B)).
Here is the explanation:
COUNTA(range): Returns number of values in a range, we can use this to get the count of rows.
INDEX(range, row, col): Returns the content of a cell, specified by row and column offset. If the column is omitted then the whole row is returned.
Examples:
INDEX(A1:C5,1,1) = A1
INDEX(A1:C5,1) = A1,B1,C1 # Whole row since the column is not specified
INDEX(A1:C5,1,2) = B1
INDEX(A1:C5,1,3) = C1
INDEX(A1:C5,2,1) = A2
INDEX(A1:C5,2,2) = B2
INDEX(A1:C5,2,3) = C2
INDEX(A1:C5,3,1) = A3
INDEX(A1:C5,3,2) = B3
INDEX(A1:C5,3,3) = C3
For the picture above, our range will be B3:B. So we will count how many values are there in range B3:B by COUNTA(B3:B) first. In the left side, it will produce 8 since there are 8 values while it will produce 9 in the right side. We also know that the last value is in the 1st column of the range B3:B so the col parameter of INDEX must be 1 and the row parameter should be COUNTA(B3:B).
PS: please upvote #bloodymurderlive's answer since he wrote it first, I'm just explaining it here.
My favorite is:
=INDEX(A2:A,COUNTA(A2:A),1)
So, for the OP's need:
=DAYS360(A2,INDEX(A2:A,COUNTA(A2:A),1))
If the column expanded only by contiguously added dates
as in my case - I used just MAX function to get last date.
The final formula will be:
=DAYS360(A2; MAX(A2:A))
Here's another one:
=indirect("A"&max(arrayformula(if(A:A<>"",row(A:A),""))))
With the final equation being this:
=DAYS360(A2,indirect("A"&max(arrayformula(if(A:A<>"",row(A:A),"")))))
The other equations on here work, but I like this one because it makes getting the row number easy, which I find I need to do more often. Just the row number would be like this:
=max(arrayformula(if(A:A<>"",row(A:A),"")))
I originally tried to find just this to solve a spreadsheet issue, but couldn't find anything useful that just gave the row number of the last entry, so hopefully this is helpful for someone.
Also, this has the added advantage that it works for any type of data in any order, and you can have blank rows in between rows with content, and it doesn't count cells with formulas that evaluate to "". It can also handle repeated values. All in all it's very similar to the equation that uses max((G:G<>"")*row(G:G)) on here, but makes pulling out the row number a little easier if that's what you're after.
Alternatively, if you want to put a script on your sheet you can make it easy on yourself if you plan on doing this a lot. Here's that scirpt:
function lastRow(sheet,column) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
if (column == null) {
if (sheet != null) {
var sheet = ss.getSheetByName(sheet);
} else {
var sheet = ss.getActiveSheet();
}
return sheet.getLastRow();
} else {
var sheet = ss.getSheetByName(sheet);
var lastRow = sheet.getLastRow();
var array = sheet.getRange(column + 1 + ':' + column + lastRow).getValues();
for (i=0;i<array.length;i++) {
if (array[i] != '') {
var final = i + 1;
}
}
if (final != null) {
return final;
} else {
return 0;
}
}
}
Here you can just type in the following if you want the last row on the same of the sheet that you're currently editing:
=LASTROW()
or if you want the last row of a particular column from that sheet, or of a particular column from another sheet you can do the following:
=LASTROW("Sheet1","A")
And for the last row of a particular sheet in general:
=LASTROW("Sheet1")
Then to get the actual data you can either use indirect:
=INDIRECT("A"&LASTROW())
or you can modify the above script at the last two return lines (the last two since you would have to put both the sheet and the column to get the actual value from an actual column), and replace the variable with the following:
return sheet.getRange(column + final).getValue();
and
return sheet.getRange(column + lastRow).getValue();
One benefit of this script is that you can choose if you want to include equations that evaluate to "". If no arguments are added equations evaluating to "" will be counted, but if you specify a sheet and column they will now be counted. Also, there's a lot of flexibility if you're willing to use variations of the script.
Probably overkill, but all possible.
This works for me. Get last value of the column A in Google sheet:
=index(A:A,max(row(A:A)*(A:A<>"")))
(It also skips blank rows in between if any)
This seems like the simplest solution that I've found to retrieve the last value in an ever-expanding column:
=INDEX(A:A,COUNTA(A:A),1)
For strictly finding the last non-empty cell in a column, this should work...
=LOOKUP(2^99, A2:A)
What about this formula for getting the last value:
=index(G:G;max((G:G<>"")*row(G:G)))
And this would be a final formula for your original task:
=DAYS360(G10;index(G:G;max((G:G<>"")*row(G:G))))
Suppose that your initial date is in G10.
I went a different route. Since I know I'll be adding something into a row/column one by one, I find out the last row by first counting the fields that have data. I'll demonstrate this with a column:
=COUNT(A5:A34)
So, let's say that returned 21. A5 is 4 rows down, so I need to get the 21st position from the 4th row down. I can do this using inderect, like so:
=INDIRECT("A"&COUNT(A5:A34)+4)
It's finding the amount of rows with data, and returning me a number I'm using as an index modifier.
for a row:
=ARRAYFORMULA(INDIRECT("A"&MAX(IF(A:A<>"", ROW(A:A), ))))
for a column:
=ARRAYFORMULA(INDIRECT(ADDRESS(1, MAX(IF(1:1<>"", COLUMN(1:1), )), 4)))
This will give the contents of the last cell:
=indirect("A"&max(ARRAYFORMULA(row(a:a)*--(a:a<>""))))
This will give the address of the last cell:
="A"&max(ARRAYFORMULA(row(a:a)*--(a:a<>"")))
This will give the row of the last cell:
=max(ARRAYFORMULA(row(a:a)*--(a:a<>"")))
Maybe you'd prefer a script. This script is way shorter than the huge one posted above by someone else:
Go to script editor and save this script:
function getLastRow(range){
while(range.length>0 && range[range.length-1][0]=='') range.pop();
return range.length;
}
One this is done you just need to enter this in a cell:
=getLastRow(A:A)
Calculate the difference between latest date in column A with the date in cell A2.
=MAX(A2:A)-A2
To find last nonempty row number (allowing blanks between them) I used below to search column A.
=ArrayFormula(IFNA(match(2,1/(A:A<>""))))
The way an amateur does it is "=CONCATENATE("A",COUNTUNIQUE(A1:A9999))", where A1 is the first cell in the column, and A9999 is farther down that column than I ever expect to have any entries. This resultant A# can be used with the INDIRECT function as needed.
Ben Collins is a Google sheets guru, he has many tips on his site for free and also offers courses. He has a free article on dynamic range names and I have used this as the basis for many of my projects.
https://www.benlcollins.com/formula-examples/dynamic-named-ranges/
Disclaimer, I have nothing to gain by referring Ben's site.
Here is a screenshot of one of my projects using dynamic ranges:
Cell D3 has this formula which was shown above except this is as an array formula:
=ArrayFormula(MAX(IF(L2s!A2:A1009<>"",ROW(2:1011))))
Cell D4 has this formula:
="L2s!A2:E"&D3
This may work:
=DAYS360(A2,INDEX(A2:A,COUNTA(A2:A)))
To pick the last in a column of arbitrary, non-empty values ignoring the header cell (A1):
=INDEX(A2:A,COUNT(A2:A))
With the introduction of LAMBDA and REDUCE functions we can now compute the row number in a single pass through the cells (Several of the solutions above filter the range twice.) and without relying on magic text or numeric values.
=lambda(rng,
REDUCE(0, rng, lambda(maxrow, cell, if(isblank(cell),maxrow,row(cell)) ) )
)(A:A)
which can be nicely packaged into a Named Function for usage like
=LAST_ROWNUM(A:A)
It works on columns with interspersed blanks, and multi-column ranges (because REDUCE iterates over the range in row-first), and partial columns (like A20:A), still returning the actual row number (not the offset within the range).
This can then be combined with Index to return the value
=DAYS360(A2, Index(A1, LAST_ROWNUM(A:A)))
(In truth, though, I suspect that the OPs date values are monotonic (even if with blanks in between), and that he could get away with
=DAYS360(A2, MAX(A2:A))
This solution is identified above as relying on the dates being "contiguous" - whether that means "no blanks" or "no missing dates" I'm not certain - but either stipulation is not necessary.)