Merging every other row in excel - excel-formula

I am looking for a way to merge every other row in an excel file. So the data looks like this:
data 1 | data 2 | data 3|
data 4 | data 5 | data 6|
data 7 | data 8 | data 9|
data 10 | data 11 | data 12|
I want:
data 1 data 4 | data 2 data 5| data 3 data 6 |
data 7 data 10 | data 8 data 11| data 9 data 12|
I tried
=OFFSET(A$1,(ROW()-1)*2,0)&" "&OFFSET(A$1,((ROW()-1)*2)+1,0) A3
From documentation but doesn't seem to work.
Any assistance is appreciated. Thank you!

I would say this question should rather be posted in superuser.com
Anyways, you could paste this in the Visual Basic Editor, just replace the ranges.
Sub merge()
For Each cell In Range("A2: D2")
cell.Offset(2, 0).Value = cell.Value & " " & cell.Offset(1, 0).Value
Next cell
End Sub

Related

Is For loop the best way to check if Cell IsNumeric?

I have to do a VBA code that check if the Cells in Column "A" IsNumber. I work with sheets that have 2k ~ 3k rows per table.
I wanna know if a For loop thru the cells in the range, is the best Optimal way to do this.
Dim tmpCell as Range
For each tmpCell in Range("A1:B5").Columns(1)
If IsNumeric(tmpCell) = True Then
tmpCell = tmpCell.Value*1
End if
next tmpCell
I need to verify if the cell is Number, because when I paste the info from a Pivot Table, one column is copied as string, not number.
Thank you, for your time.
Edit:
My table is something like this.
The numbers in the "A" Column is in string, not number.
| A1 | B1 | C1 |
1| 1234 | 1 | 2 |
2| 5678 | 2 | 4 |
3| 9012 | 3 | 5 |
4|Total | 5 | 11 |

Apply function to an array matching a criterium

perhaps I'm just unable to formulate the question, but I was unable to find any matches for this, however is there a way you can return an array of all the matching cells matching criteria?
Let's say the following example
1 2
|---------------------|------------------|
1| A | B |
|---------------------|------------------|
2| 1 | 2 |
|---------------------|------------------|
3| 1 | 3 |
|---------------------|------------------|
4| 1 | 12 |
|---------------------|------------------|
5| 2 | 8 |
|---------------------|------------------|
Now in C2, I need to find a way to find a MAX value, out of entire B column, for all the cells that have value 1 in column A.
Now this would be a relatively simple array filter in vba, however I'm trying to achieve this by somehow using only excel formulas.
AFAIK, all the methods, like =INDEX() or =VLOOKUP() can only find a single closest (exact) match. Is there however to return an array of all the matching results?
I'd presume it would go something like
=INDEX($A$2:$B$5; MATCH($A$2; $A$2:$A$5; 0); 1)
However once again issue here being, this would stop on the first occurance, rater than go through the entire array.
Probably only thing I can think of is to exhaustively go over each and every number, return in a separate value every occurance (in a matrix) and then add the number, but that seems like way too much of a hassle
Expected result:
1 2
|---------------------|------------------|------------------|
1| A | B | C |
|---------------------|------------------|------------------|
2| 1 | 2 | 12 |
|---------------------|------------------|------------------|
3| 1 | 3 | 12 |
|---------------------|------------------|------------------|
4| 1 | 12 | 12 |
|---------------------|------------------|------------------|
5| 2 | 8 | 8 |
|---------------------|------------------|------------------|
SUMPRODUCT + MAX works for older excel versions too:
=SUMPRODUCT(MAX(($A$1:$A$4=A1)*$B$1:$B$4))
Tested this:
=MAXIFS(B:B,A:A,A1)
Returns your desired result.

Excel - Transpose data from multiple rows to single column with matched value

Ok, so I have some data that I want to convert from multiple rows to multiple columns.
My input data looks loosely like this -
+----------+----------------+-----------------+
| SKU | Attribute Name | Attribute Value |
+----------+----------------+-----------------+
| Product1 | Colour | Black |
| Product1 | Size | Large |
| Product1 | Height | 20cm |
| Product1 | Width | 40cm |
| Product2 | Colour | Red |
| Product2 | Width | 30cm |
| Product2 | Size | Large |
| Product3 | Height | 25cm |
| Product3 | Width | 30cm |
| Product3 | Length | 90cm |
| Product3 | Weight | 5kg |
| Product3 | Size | Large |
| Product3 | Colour | Blue |
+----------+----------------+-----------------+
What I want to achieve is an output like this -
+----------+--------+--------+--------+-------+--------+-------+
| SKU | Colour | Height | Length | Size | Weight | Width |
+----------+--------+--------+--------+-------+--------+-------+
| Product1 | Black | 20cm | | Large | | 40cm |
| Product2 | Red | | | Large | | 30cm |
| Product3 | Blue | 25cm | 90cm | Large | 5kg | 30cm |
+----------+--------+--------+--------+-------+--------+-------+
I've tried Pivot tables, but you can only return numeric values, rather than the text values I'm looking for.
I know I could probably achieve it using a number of step looking up values and filling them, but I feel like there should be a more simplistic way to achieve this. Maybe it's something better achieved in database rather than a spreadsheet.
Any help would be very much appreciated.
You can do this in ̶5̶ ̶s̶t̶e̶p̶s̶ 4 steps with Powerquery. This is in-built for 2016 and a free add-in from Microsoft from 2013 on wards ( or 2010 Professional Plus with Software Assurance). See info https://www.microsoft.com/en-gb/download/details.aspx?id=39379
The advantage is you can easily add rows to the source and simply refresh the query.
1) You select any cell in the range, then in 2016 Get & Transform tab, earlier version use the Powerquery tab, select data from table. A window will pop up with your range of data in:
2) Transform > Pivot column > Attribute Name column for Attribute Value in Values Column (used advanced options to select "Don't aggregate")
3) Drag columns around to desired arrangement
4) Home > Close and load to sheet
Here is a version without the column re-ordering
Edit:
Thanks to #Ron Rosenfeld for reminding me that truly null values don't need replacing with blanks as they will appear as blanks when written to the sheet.
So this step was removed:
4) Highlight columns to replace nulls in and go to transform > replace values > and
Value to Find: null
Replace With:
You could do this using a helper column and then match it using index + match. Not as simple as you thought, but does work.
1) Add helper column to your data (call it 'Helper'). =concat(SKU,'Attribute Name')
2) Use a pivot to get a unique list of SKUs in the rows so that it's easy to update once the data changes. (I'm assuming this is in column A and values start at row 4).
3) Use another pivot to get a unique list of Attributes in the columns next to the other pivot. Then you have the structure of your results. (I'm assuming the first value is in B3).
4) Index match the values of the table =index('Attribute Value', match(concat($A4,B$3),'Helper',0))
Note though that this only works when each combination of SKU and Attribute is unique.
This assumes that the data is in columns A through C:
Sub croupier()
Dim i As Long, N As Long, vA As String, vB As String, vC As String
Dim rw As Long, cl As Long
' setup column headers
Columns(2).SpecialCells(2).Offset(1).Copy Range("D1")
Columns(4).RemoveDuplicates Columns:=1, Header:=xlNo
Columns(4).SpecialCells(2).Copy
Range("E1").PasteSpecial Transpose:=True
Columns(4).SpecialCells(2).Clear
' setup row headers
Columns(1).SpecialCells(2).Copy Range("D1")
Columns(4).RemoveDuplicates Columns:=1, Header:=xlYes
' deal the data
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = 2 To N
vA = Cells(i, 1)
vB = Cells(i, 2)
vC = Cells(i, 3)
cl = Rows(1).Find(what:=vB, after:=Range("A1")).Column
rw = Columns(4).Find(what:=vA, after:=Range("D1")).Row
Cells(rw, cl) = vC
Next i
End Sub

How to loop throgh a set of rows, count.if by each row, then sum the total result?

As an equivalent simplified example of what i intend, there is this worksheet with any sequence of 5 numbers beetween 1-9 each from columns A to E and for many rows:
| A| B| C| D| E|
1 | 1| 5| 6| 8| 9|
2 | 2| 5| 7| 8| 9|
...
50| 1| 3| 4| 6| 7|
Then I want to check for how many combinations of any two numbers occur by each row along all the rows and filling a combination array with the result:
| 1| 2| 3| 4| 5| 6| 7| 8| 9|
1| | | | | | | | | |
2| | | | | | | | | |
3| | | | | | | | | |
4| | | | | | | | | |
5| | | | x| | | | | |
6| | | | | | | | | |
7| | | | | | | | | |
8| | | | | | | | | |
9| | | | | | | | | |
Above, "x" would represent the value of in how many rows there is any occurance of the combination of the numbers 4 and 5.
I achieved my goal easily by VBA code, but wanted to know how to do this by excel-formula, since it generally will be faster.
Just in case anyone one want to check the VBA code that already works for this task:
Sub NPairs()
Dim Rn As Long
Dim Cn As Long
For Nrow = 2 To 10
For Ncol = 2 To 10
If NCol = NRow Then GoTo NextN 'Skip, cause would search the combination of the same numbers.
Rn = Plan2.Cells(NRow, 1).Value2
Cn = Plan2.Cells(1, NCol).Value2
Plan2.Cells(Nrow, Ncol) = NMatch(Rn, Cn)
NextN:
Next
Next
End Sub
Private Function Nmatch(Rnumber As Long, Cnumber As Long) As Long
Lastrow = Plan1.Cells(Plan1.Rows.Count, "A").End(xlUp).Row
M = 0
For R = 2 To Lastrow
For C = 1 To 5
If Plan1.Cells(R, C).Value2 = Rnumber Then
For Cl = 1 To 5
If Plan1.Cells(R, Cl).Value2 = Cnumber Then M = M + 1
Next
End If
Next
Next
Nmatch = M
End Function
This could be fastened by using array or dictionary, I know. What I want to know is if that is possible to do the same, in a more simple way, by excel-formula.
If your concern is speed, then VBA will probably be faster in this case. But here is an idea to do it with formulas only:
Create an intermediate matrix with as many rows as in the source matrix and a column for each number (1 .. 9). Use a formula to indicate whether the corresponding row contains the number identified by the column.
Based on this intermediate matrix, look for the rows which have TRUE for the two numbers of interest.
You can then hide the intermediate matrix if so desired.
Here is how it would look:
The middle matrix is the intermediate one. The formula in G2 is:
=COUNTIF($A2:$E2, G$1)
You can copy it to the other cells of that matrix
The rightmost matrix is the final result. The formula in R2 is:
=IF(R$1=$Q2, COUNTIFS(INDEX($G$2:$O$9, 0, R$1),">1"),
COUNTIFS(INDEX($G$2:$O$9, 0, R$1),">0", INDEX($G$2:$O$9, 0, $Q2), ">0"))
The INDEX function is used to retrieve the appropriate column in the intermediate matrix. The one column in the intermediate matrix is chosen based on the current row (in the final matrix) and the other one is based on the current column. Both must have the value TRUE (in the same row) to be counted.
After your comment, I wrapped the formula in an IF to deal with the case of the main diagonal: in that case the single number must occur more than once in a row for the latter to be counted.
You can download the above sheet from Google docs
=SUM(IF(ISNUMBER(SEARCH("*"&J$1&"*"&$I2&"*",$A$1:$A$50&$B$1:$B$50&$C$1:$C$50&$D$1:$D$50&$E$1:$E$50)),1,IF(ISNUMBER(SEARCH("*"&$I2&"*"&J$1&"*",$A$1:$A$50&$B$1:$B$50&$C$1:$C$50&$D$1:$D$50&$E$1:$E$50)),1,0)))
This is an array formula, while still in the formula bar hit Ctrl + Shift + Enter
Using wildcards with SEARCH() we can look for the numbers within built strings, then reverse the serach order to catch both instances. I build a binary array based of the results and SUM() them.
* equates to any number of any character (can also be 0 characters). Using this we can establish whether the 2 numbers appear anywhere in the 5 positions, this is then flipped to catch if they are in the other order.
Using a similar approach to #trincot, with an intermediate table, but this table would be ten columns with the set of ten pairs of digits from the source table:
Then use Countif() to count the occurrences of the pairs in a separate table:
Using named ranges would make the formulas even simpler.

Row Numbers in Excel Table

I have the following basic table:
1|
2| Title....
3|
4|
5| | Row Index | Type | Etc... |
6| | 1 | abc | ..... |
7| | 2 | def | ..... |
8| | 3 | ghi | ..... |
9| | 4 | jkl | ..... |
Note that the table does not start on Excel row 1. Technically ROW()-5 would work, but I do not want to hardcode the actual row the table starts on.
My formula for Row Index is:
=ROW()-CELL("row")+1
This works fine, except for when you edit another cell in the table. It seems that the formula assumes the row you edit is index 0 and starts the row count from there.
For instance, if I were to edit a cell in row 3 in the above table, the Row Index values would look like this:
| Row Index | Type | Etc... |
| -1 | abc | ..... |
| 0 | def | ..... |
| 1 | ghi | ..... |
| 2 | jkl | ..... |
After each edit, I think have to re-edit a cell in the top row to get the Row Index values correct again.
Is there a reliable way to display row numbers in a table?
If it is an actual Excel Table (Insert tab > Table or Home tab > Format as Table):
=ROW()-ROW([#Headers])
or
=ROW()-ROW(Table1)+1
Otherwise, you can use the absolute address:
=ROW()-ROW($5:$5)
Remove the CELL("row") and just use the formula
=ROW() - 5
The ROW function returns the row number of the cell containing the formula, which is what you want.
The CELL function, on the other hand, returns information about the last changed cell, which is why you see the strange behavior.
CELL(info_type, [reference])
Reference   Optional. The cell that you want information about. If omitted, the information specified in the Info_type argument is returned for the last cell that was changed. ...
Even if CELL returns information about the current cell, what you would get from ROW() - CELL("Row", <current_cell>) + 1 would be the constant 1 because the two functions cancel each other.

Resources