Combine cell strings when condition is matched, and remove duplicates? - excel

I'm over my head here, but hoping someone can help.
Would like C3 to display all the strings from C15 to C60 for rows where column E matches B3, and remove duplicates / only display uniques.
Also, I would like D3 to display the strings from D15 to D60 as the prior question, however the cells potentially contain comma separated values - is there a way I can do as above but treat the comma separated values as separate strings?
screenshot and spreadsheet to download.
Thanks in advance for anyone taking a look.
Joe

excel have a function to remove duplicate data, did you try it?
just copy your origin data then remove duplicate.

Retrieve Possibly Separated Unique Data
Usage:
Copy the code into a standard module and in Excel use the following formulas:
in Cell C3 =CritJoe(C$15:C$60,$E$15:$E$60,$B3)
in Cell D3 =CritJoe(D$15:D$60,$E$15:$E$60,$B3,",")
The Code
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Retrieves unique ((comma) separated) (ResultSeparator) data
' determined by a criteria (Criteria) in a specified column
' (CriteriaRange) from another specified column (SourceRange)
' possibly containing (comma) separated (StringSeparator) strings.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function CritJoe(SourceRange As Range, CriteriaRange As Range, _
Criteria As String, Optional StringSeparator As String = "", _
Optional ResultSeparator As String = ", ") As String
Dim vntS ' Source Array (1-based, 2-dimensional)
Dim vntC ' Criteria Array (1-based, 2-dimensional)
Dim vntSS ' Source String Array (0-based, 1-dimensional)
Dim vntR ' Resulting Array (0-based, 1-dimensional)
Dim i As Long ' Source & Criteria Array Elements Counter
Dim j As Long ' Resulting Array Elements Counter
Dim k As Long ' Source String Array Elements Counter
Dim UB As Long ' Current Resulting Array's Upper Bound
Dim strS As String ' Current Source String
Dim strR As String ' Resulting String
' Check if SourceRange and CriteriaRange have the same number of rows and
' have the same first row number.
If SourceRange.Rows.Count <> CriteriaRange.Rows.Count Or _
SourceRange.Rows(1).Row <> CriteriaRange.Rows(1).Row Then GoTo RowsError
' Note: The relevant data has to be in the first column of each range
' if (accidentally) more columns have been selected.
' Copy first column of the Ranges to Arrays.
vntS = SourceRange.Cells(1).Resize(SourceRange.Rows.Count)
vntC = CriteriaRange.Cells(1).Resize(CriteriaRange.Rows.Count)
' Write relevant data to Resulting Array.
For i = 1 To UBound(vntS)
' To avoid "Case/Space issues", "parts" of the following can be used:
' If Upper(Trim(vntC(i, 1))) = Upper(Trim(Criteria)) Then
' ... instead of the following line:
If vntC(i, 1) = Criteria Then
strS = vntS(i, 1)
If StringSeparator <> "" Then
' Write Resulting String to Resulting Array using
' StringSeparator.
GoSub SplitString
Else
' Write Resulting String to Resulting Array without
' using StringSeparator.
GoSub StringToArray
End If
End If
Next
' Write relevant data from Resulting Array to Resulting String.
If IsArray(vntR) Then
strR = vntR(0)
If UBound(vntR) > 0 Then
For j = 1 To UBound(vntR)
strR = strR & ResultSeparator & vntR(j)
Next
End If
End If
CritJoe = strR
Exit Function
' Write Resulting String to Resulting Array using StringSeparator.
SplitString:
vntSS = Split(strS, StringSeparator)
For k = 0 To UBound(vntSS)
strS = Trim(vntSS(k))
GoSub StringToArray
Next
Return
' Write Resulting String to Resulting Array.
StringToArray:
If IsArray(vntR) Then
' Handle all except the first element in Resulting Array.
UB = UBound(vntR)
For j = 0 To UB
If vntR(j) = strS Then Exit For
Next
If j = UB + 1 Then
ReDim Preserve vntR(j): vntR(j) = strS
End If
Else
' Handle only first element in Resulting Array.
ReDim vntR(0): vntR(0) = strS
End If
Return
RowsError:
CritJoe = "Rows Error!"
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

As I wrote, it's relatively simple with Power Query, available in Excel 2010+. It takes longer to type out the steps then to create it :-).
All can be done from the UI
Remove the Scene and Video Columns
Split the Cast column by the comma delimiter
Select the Location and Cast columns and Transform/Trim to eliminate unwanted spaces
Select all three columns and Remove Rows/Duplicates
Group By Recording Block Operation:= All Rows
Name the Column Grouped
Add Custom Column for the Locations: Formula =
List.Distinct(Table.Column([Grouped],"Location"))
note the new column name in the dialog box
Add another Custom Column for the Cast: Formula =
List.Distinct(Table.Column([Grouped],"Cast"))
Select the double-headed arrow at the top of the new columns
Extract Values from the drop down and select a delimiter -- I used the Custom --> comma space
Close and Load to wherever you want on the worksheet.
Of note, this workbook can be saved as an xlsx file.
For interest, here is the M-Code generated.
M Code
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Video", Int64.Type}, {"Scene", Int64.Type}, {"Location", type text}, {"Cast", type text}, {"Recording Block", type text}}),
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"Video", "Scene"}),
#"Split Column by Delimiter" = Table.ExpandListColumn(Table.TransformColumns(#"Removed Columns", {{"Cast", Splitter.SplitTextByDelimiter(",", QuoteStyle.Csv), let itemType = (type nullable text) meta [Serialized.Text = true] in type {itemType}}}), "Cast"),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Cast", type text}}),
#"Trimmed Text" = Table.TransformColumns(#"Changed Type1",{{"Cast", Text.Trim, type text}, {"Location", Text.Trim, type text}}),
#"Removed Duplicates" = Table.Distinct(#"Trimmed Text"),
#"Grouped Rows" = Table.Group(#"Removed Duplicates", {"Recording Block"}, {{"Grouped", each _, type table [Location=text, Cast=text, Recording Block=text]}}),
#"Added Custom" = Table.AddColumn(#"Grouped Rows", "Locations", each List.Distinct(Table.Column([Grouped],"Location"))),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "Cast", each List.Distinct(Table.Column([Grouped],"Cast"))),
#"Extracted Values" = Table.TransformColumns(#"Added Custom1", {"Cast", each Text.Combine(List.Transform(_, Text.From), ", "), type text}),
#"Extracted Values1" = Table.TransformColumns(#"Extracted Values", {"Locations", each Text.Combine(List.Transform(_, Text.From), ", "), type text})
in
#"Extracted Values1"

Related

Restructure Excel table with VBA

I have an Excel table source (extract is below):
Models are changing (adding new names, removing), so does change Week number in Columns (from Now till end of the year)
I need to restructure it so that it could look like this:
So that it could be normally used for further querying.
In each row there must be model name, for each model there should be Week number and corresponding matching Quantity taken from the table itself (on the intersection of Model X Week from original table).
I was smashing my head against the wall on how it can be realized in VBA. Couldn't restructure it with simple code.
try this code, just change the name of your sheets I used 2, the first is the source and the second is the destination, I hope help you
good Luck
Sub RestructureTable()
Const SourceSheetName = "Source", DestinationSheetName = "Restructure" 'Your sheet names
Dim nRowCounter As Double, nColumnSourceCounter As Double, nRowSourceCounter As Double
'--------
'-------Set the headers in destination sheet
Sheets(DestinationSheetName).Range("A1") = "Models" 'Replace "Models" as you need
Sheets(DestinationSheetName).Range("B1") = "Week" 'Replace "Week" as you need
Sheets(DestinationSheetName).Range("C1") = "Qty" 'Replace "Qty" as you need
'--------
'----------------------------------------------------
Sheets(SourceSheetName).Select 'Select the source sheet
Range("A2").Select ' select the first cell with data
nRowCounter = 2 ' Start in 2 cuase headers
'---------------------------------------------------
nRowSourceCounter = ThisWorkbook.Application.WorksheetFunction.CountA(Range("A:A")) 'count rows
nColumnSourceCounter = ThisWorkbook.Application.WorksheetFunction.CountA(Range("1:1")) 'count columns
For r = 2 To nRowSourceCounter
For c = 2 To nColumnSourceCounter
'Model
Sheets(DestinationSheetName).Range("A" & nRowCounter) = Sheets(SourceSheetName).Cells(r, 1)
'Header:Week
Sheets(DestinationSheetName).Range("B" & nRowCounter) = Sheets(SourceSheetName).Cells(1, c)
'Qty
Sheets(DestinationSheetName).Range("C" & nRowCounter) = Sheets(SourceSheetName).Cells(r, c)
nRowCounter = nRowCounter + 1
Next c
Next r
End Sub
You could do this with VBA but you could also do it with only a few steps using Power Query.
VBA Method
Here's code to do it with VBA, it assumes the data to restructure is in a sheet named Data and starts at A1.
In this code the restructured data is put on a new sheet but you could change that to put it on an existing sheet.
Option Explicit
Sub RestructureData()
Dim ws As Worksheet
Dim arrDataIn As Variant
Dim arrDataOut() As Variant
Dim cnt As Long
Dim idxCol As Long
Dim idxRow As Long
arrDataIn = Sheets("Data").Range("A1").CurrentRegion.Value
ReDim arrDataOut(1 To (UBound(arrDataIn, 1) - 1) * (UBound(arrDataIn, 2) - 1), 1 To 3)
For idxRow = LBound(arrDataIn, 1) + 1 To UBound(arrDataIn, 1)
For idxCol = LBound(arrDataIn, 2) + 1 To UBound(arrDataIn, 2)
cnt = cnt + 1
arrDataOut(cnt, 1) = arrDataIn(idxRow, 1)
arrDataOut(cnt, 2) = arrDataIn(1, idxCol)
arrDataOut(cnt, 3) = arrDataIn(idxRow, idxCol)
Next idxCol
Next idxRow
Set ws = Sheets.Add ' can be set to existing worksheet
ws.Range("A1:C1").Value = Array("Model", "Week", "Quantity")
ws.Range("A2").Resize(cnt, 3).Value = arrDataOut
End Sub
Power Query Method
Go to the sheet with the data, then go to the Data>Get & Transform Data tab.
Select From Table/Range, make sure all the data is selected and Does your data have headers? is ticked.
In Power Query select the Model column, right click and select Unpivot Other Columns.
Rename the Attribute column 'Week' and the value column 'Quantity' by double click each column header.
Click Close & Load to return the data to Excel.
This is the M Code those steps produce.
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Models", type text}, {"2021-03-29_(W13)", Int64.Type}, {"2021-04-05_(W14)", Int64.Type}, {"2021-04-12_(W15)", Int64.Type}, {"2021-04-19_(W16)", Int64.Type}, {"2021-04-26_(W17)", Int64.Type}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"Models"}, "Attribute", "Value"),
#"Renamed Columns" = Table.RenameColumns(#"Unpivoted Other Columns",{{"Attribute", "Week"}, {"Value", "Quantity"}})
in
#"Renamed Columns"

How to combine 2 VBA functions based on condition of 1 function?

I have a dataset where contact information and names are correlated to companies that the individual has worked for. 1 individual can be associated with many companies. I want to consolidate information of the individuals but keep information on the different company names.
I have a VBA function that can remove duplicates of rows (name and contact info) and another VBA function that can merge two separate cells (company names) into 1 merged cell. The data isn't sorted by any particular field.
I would like to create a function that will remove duplicates of rows AND THEN merge the company name cells BUT ONLY FOR individuals that have duplicate rows removed (meaning that the individual is associated with more than 1 company).
Thanks for any help!
Sample of raw data format:
this is the function and result of VBA function 1:
Sub RemoveDuplicates()
'UpdatebyExtendoffice20160918
Dim xRow As Long
Dim xCol As Long
Dim xrg As Range
Dim xl As Long
On Error Resume Next
Set xrg = Application.InputBox("Select a range:", "Kutools for Excel", _
ActiveWindow.RangeSelection.AddressLocal, , , , , 8)
xRow = xrg.Rows.Count + xrg.Row - 1
xCol = xrg.Column
'MsgBox xRow & ":" & xCol
Application.ScreenUpdating = False
For xl = xRow To 2 Step -1
If Cells(xl, xCol) = Cells(xl - 1, xCol) Then
Cells(xl, xCol) = ""
End If
Next xl
Application.ScreenUpdating = True
End Sub
Function 2 is below and the module just concatenates and merges cells, but I don't know how to write a function that will only apply where the individual has had duplicate rows removed (meaning that individual is associated with multiple companies).
Sub MergeCells()
Dim xJoinRange As Range
Dim xDestination As Range
Set xJoinRange = Application.InputBox(prompt:="Highlight source cells to merge", Type:=8)
Set xDestination = Application.InputBox(prompt:="Highlight destination cell", Type:=8)
temp = ""
For Each Rng In xJoinRange
temp = temp & Rng.Value & " "
Next
xDestination.Value = temp
End Sub
I would approach this differently and use Power Query, available in Excel 2010+.
Power Query as a "Group By" method where you can select the columns you want to group by -- in your case it would be all the columns except the Company column. You can then concatentate the company column using linefeeds, and obtain the result you desire.
Data --> Get & Transform Data --> From Table/Range
Select all the columns except Company and Group By
The Operation is All Rows
Add Custom Column (to split out the company names with formula:
Table.Column([Grouped],"Company")
Select the Double-headed arrow at the top of the custom column
Extract values from list
Use the line feed for the separator #(lf)
Close and Load to
You may have to do some custom formatting for the phone number, and also set Word Wrap for the company column.
Here is the generated MCode:
let
Source = Excel.CurrentWorkbook(){[Name="Table3"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Email", type text}, {"Phone", Int64.Type}, {"First Name", type text}, {"Last Name", type text}, {"Company", type text}}),
#"Grouped Rows" = Table.Group(#"Changed Type", {"Email", "Phone", "First Name", "Last Name"}, {{"Grouped", each _, type table [Email=text, Phone=number, First Name=text, Last Name=text, Company=text]}}),
#"Added Custom" = Table.AddColumn(#"Grouped Rows", "Company", each Table.Column([Grouped],"Company")),
#"Extracted Values" = Table.TransformColumns(#"Added Custom", {"Company", each Text.Combine(List.Transform(_, Text.From), "#(lf)"), type text})
in
#"Extracted Values"
And here are the results:

How do I return a criteria after summing up values based on the criteria given?

I have a sheet that looks similar to this:
So column A and column B are combined along with a number in column C. What I am trying to do is add up each value in each column (for example: add each C column for each time "Cat" appears, and "Dog" and "Grass", etc) and then find the value in columns A and B that is the highest, and return that value. So for example, in my example above, Dog would be the formula result because it's C column totals to 28. Is there a formula (or, most likely, a combination of formulas) that can accomplish this?
Thank you!
just to show, the formula would be:
=INDEX(INDEX(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),N(IF({1},MODE.MULT(IF(ROW($1:$24)=MATCH(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),0),ROW($1:$24)*{1,1}))))),MATCH(MAX(SUMIFS(C:C,A:A,INDEX(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),N(IF({1},MODE.MULT(IF(ROW($1:$24)=MATCH(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),0),ROW($1:$24)*{1,1}))))))+SUMIFS(C:C,B:B,INDEX(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),N(IF({1},MODE.MULT(IF(ROW($1:$24)=MATCH(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),0),ROW($1:$24)*{1,1}))))))),SUMIFS(C:C,A:A,INDEX(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),N(IF({1},MODE.MULT(IF(ROW($1:$24)=MATCH(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),0),ROW($1:$24)*{1,1}))))))+SUMIFS(C:C,B:B,INDEX(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),N(IF({1},MODE.MULT(IF(ROW($1:$24)=MATCH(INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),INDEX(A1:B12,N(IF({1},INT((ROW($1:$24)-1)/2)+1)),N(IF({1},MOD((ROW($1:$24)-1),2)+1))),0),ROW($1:$24)*{1,1})))))),0))
This is an array formula and must be confirmed with Ctrl-Shift-Enter instead of Enter when exiting edit mode.
It gets a little more manageable with the new dynamic array formulas:
=INDEX(UNIQUE(INDEX(A1:B12,N(IF({1},INT(SEQUENCE(24,,0)/2)+1)),N(IF({1},MOD(SEQUENCE(24,,0),2)+1)))),MATCH(MAX(SUMIFS(C:C,A:A,UNIQUE(INDEX(A1:B12,N(IF({1},INT(SEQUENCE(24,,0)/2)+1)),N(IF({1},MOD(SEQUENCE(24,,0),2)+1)))))+SUMIFS(C:C,B:B,UNIQUE(INDEX(A1:B12,N(IF({1},INT(SEQUENCE(24,,0)/2)+1)),N(IF({1},MOD(SEQUENCE(24,,0),2)+1)))))),SUMIFS(C:C,A:A,UNIQUE(INDEX(A1:B12,N(IF({1},INT(SEQUENCE(24,,0)/2)+1)),N(IF({1},MOD(SEQUENCE(24,,0),2)+1)))))+SUMIFS(C:C,B:B,UNIQUE(INDEX(A1:B12,N(IF({1},INT(SEQUENCE(24,,0)/2)+1)),N(IF({1},MOD(SEQUENCE(24,,0),2)+1))))),0))
But we can use helper columns with the dynamic array formula.
In one cell we put:
=UNIQUE(INDEX(A1:B12,N(IF({1},INT(SEQUENCE(24,,0)/2)+1)),N(IF({1},MOD(SEQUENCE(24,,0),2)+1))))
I put it in E1, then I refer to that with the sumifs:
=SUMIFS(C:C,A:A,E1#)+SUMIFS(C:C,B:B,E1#)
I put that in F1, then use INDEX/MATCH:
=INDEX(E1#,MATCH(MAX(F1#),F1#,0))
Doing it the long way with normal formulas, one would need to copy paste the two columns one below the other and use Remove duplicate on the data tab to get a unique list:
Then use the formula in F1:
=SUMIFS(C:C,B:B,E1)+SUMIFS(C:C,A:A,E1)
And copy down the list. then use the INDEX/MATCH:
=INDEX(E:E,MATCH(MAX(F:F),F:F,0))
to return the desired value.
And just to be thorough here is why vba is better for this. Put this in a module:
Function myMatch(RngA As Range, RngB As Range, sumRng As Range)
If RngA.Cells.Count <> RngB.Cells.Count Or RngA.Cells.Count <> sumRng.Cells.Count Or RngB.Cells.Count <> sumRng.Cells.Count Then
myMatch = CVErr(xlErrValue)
Exit Function
End If
Dim arrA As Variant
arrA = RngA.Value
Dim arrB As Variant
arrB = RngB
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim j As Long
For j = 1 To 2
Dim i As Long
For i = 1 To UBound(arrA)
Dim uRec As String
uRec = IIf(j = 1, arrA(i, 1), arrB(i, 1))
Dim smRec As Double
smRec = Application.SumIfs(sumRng, RngA, IIf(j = 1, arrA(i, 1), arrB(i, 1))) + Application.SumIfs(sumRng, RngB, IIf(j = 1, arrA(i, 1), arrB(i, 1)))
On Error Resume Next
dict.Add uRec, smRec
On Error GoTo 0
Next i
Next j
Dim mx As Double
mx = 0
Dim temp As String
temp = ""
Dim key As Variant
For Each key In dict.Keys
If dict(key) > mx Then
temp = key
mx = dict(key)
End If
Next key
myMatch = temp
End Function
Then all you need to do on the worksheet is call it as a normal function listing the three areas:
=myMatch(A1:A12,B1:B12,C1:C12)
You can also solved the case using Power Query.
Steps are:
Add your source data (which is the three column table) to the Power Query Editor;
Use Merge Columns function under the Transform tab to merge the first two columns by a delimiter, say semicolon ;;
Use Split Columns function under the Transform tab to split the merged column by the same delimiter, say semicolon ;, and make sure in the Advanced Options choose to put the results into Rows;
Use Group By function to group the last column by the Merged column and set SUM as the function;
Lastly, sort the last column Descending.
You can Close & Load the result to a new worksheet (by default).
Here are the Power Query M Codes behind the scene for your reference only. All steps are using built-in functions which are straight forward and easy to execute.
let
Source = Excel.CurrentWorkbook(){[Name="Table2"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Column1", type text}, {"Column2", type text}, {"Column3", Int64.Type}}),
#"Merged Columns" = Table.CombineColumns(#"Changed Type",{"Column1", "Column2"},Combiner.CombineTextByDelimiter(";", QuoteStyle.None),"Merged"),
#"Split Column by Delimiter" = Table.ExpandListColumn(Table.TransformColumns(#"Merged Columns", {{"Merged", Splitter.SplitTextByDelimiter(";", QuoteStyle.Csv), let itemType = (type nullable text) meta [Serialized.Text = true] in type {itemType}}}), "Merged"),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Merged", type text}}),
#"Grouped Rows" = Table.Group(#"Changed Type1", {"Merged"}, {{"Sum", each List.Sum([Column3]), type number}}),
#"Sorted Rows" = Table.Sort(#"Grouped Rows",{{"Sum", Order.Descending}})
in
#"Sorted Rows"
Let me know if you have any questions. Cheers :)

Excel Split cell with multiple lines into rows for entire table

In Excel (2016), I have some data that looks like this:
Based on a particular column, in this example the 'IPAddress' column, if there are multiple lines in the cell, separate the string into a new row and copy the remaining data into that row.
This is what I am looking for after the script or whatever completes.
I'm using the follow code from: Split cell with multiple lines into rows
Sub tes_5()
Dim cell_value As Variant
Dim counter As Integer
'Row counter
counter = 1
'Looping trough A column define max value
For i = 1 To 10
'Take cell at the time
cell_value = ThisWorkbook.ActiveSheet.Cells(i, 1).Value
'Split cell contents
Dim WrdArray() As String
WrdArray() = Split(cell_value, vbLf)
'Place values to the B column
For Each Item In WrdArray
ThisWorkbook.ActiveSheet.Cells(counter, 2).Value = Item
counter = counter + 1
Next Item
Next i
End Sub
That separates out the IPAddress column, but does not add the data for the other cells in the new row.
Text to columns doesn't work and Power Query (https://www.quora.com/Is-there-a-way-in-excel-to-bulk-split-cells-with-multiple-lines-inside-into-new-rows-without-overwriting-the-existing-data-below) doesn't work either.
Any other suggestions?
Update:
Just learned that by default, Excel puts a comma at the beginning of the delimiter field, which was causing my delimiter to not work when choosing line feed.
If you remove the leading comma, you "should" (like I did), get the desired results.
Pretty simple with Power Query
All you need to do is split the IPAddress column by the linefeed character into Rows
Split Column dialog from UI
M-Code
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Server Name", type text}, {"Serial Number", type text}, {"OS", type text}, {"IPAddress", type text}}),
#"Split Column by Delimiter" = Table.ExpandListColumn(Table.TransformColumns(#"Changed Type", {{"IPAddress", Splitter.SplitTextByDelimiter("#(lf)", QuoteStyle.Csv), let itemType = (type nullable text) meta [Serialized.Text = true] in type {itemType}}}), "IPAddress")
in
#"Split Column by Delimiter"
Try this, assuming your data starts in A2:
Sub x()
Dim r As Long, v As Variant
For r = Range("A" & Rows.Count).End(xlUp).Row To 2 Step -1
v = Split(Cells(r, 4), vbLf)
If UBound(v) > 0 Then
Cells(r + 1, 1).Resize(UBound(v), 4).Insert shift:=xlDown
Cells(r + 1, 1).Resize(UBound(v), 3).Value = Cells(r, 1).Resize(, 3).Value
Cells(r, 4).Resize(UBound(v) + 1).Value = Application.Transpose(v)
End If
Next r
End Sub

Excel 365 - Getting Data Table w/ Images from Web

I am using Office 365 and I am trying to get a data table from the web and import it in an Excel sheet together with the images. Here is the table which I am trying to import:
https://royaleapi.com/clan/90R9VPP9/war/analytics
http://i63.tinypic.com/2s655kx.jpg
As you can see from the table, there are images in cells representing certain statuses which contain meaningful data:
Medal = win
Cross = loss
Empty medal slot = missing in action
Empty cell = didn't participate
I click on data and select From Web, where I paste the link. Excel brings up the following, where I select Table 0 for the info I need.
http://i67.tinypic.com/2lmb4u0.jpg
After I click load, the generated table is as below. As you can see, there are no images which denote the status of the person, this method only gets the texts etc. but the cells which should have contained the images are not pulled.
http://i67.tinypic.com/n3kzz5.jpg
After searching online, I've managed to put together a code to isolate the images in another query (Query1) which you can find below. This query gives the images but doesn't place them in cells, I've just managed to get to the images themselves :)
let
Source = Table.FromColumns({Lines.FromBinary(Web.Contents("https://royaleapi.com/clan/8P2V9VYL/war/analytics"), null, null, 65001)}),
#"Filtered Rows" = Table.SelectRows(Source, each Text.Contains([Column1], "src=""/static/img/ui")),
#"Split Column by Delimiter" = Table.SplitColumn(#"Filtered Rows", "Column1", Splitter.SplitTextByEachDelimiter({"src=""/"}, QuoteStyle.None, true), {"Column1.1", "Column1.2"}),
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Column1.1", type text}, {"Column1.2", type text}}),
#"Split Column by Delimiter1" = Table.SplitColumn(#"Changed Type", "Column1.2", Splitter.SplitTextByEachDelimiter({""""}, QuoteStyle.None, false), {"Column1.2.1", "Column1.2.2"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter1",{{"Column1.2.1", type text}, {"Column1.2.2", type text}}),
#"Removed Columns" = Table.RemoveColumns(#"Changed Type1",{"Column1.1", "Column1.2.2"}),
#"Added Custom" = Table.AddColumn(#"Removed Columns", "https", each "https://royaleapi.com/"),
#"Reordered Columns" = Table.ReorderColumns(#"Added Custom",{"https", "Column1.2.1"}),
#"Merged Columns" = Table.CombineColumns(#"Reordered Columns",{"https", "Column1.2.1"},Combiner.CombineTextByDelimiter("", QuoteStyle.None),"Merged"),
#"Renamed Columns" = Table.RenameColumns(#"Merged Columns",{{"Merged", "Images"}}),
#"Duplicated Column" = Table.DuplicateColumn(#"Renamed Columns", "Images", "Images - Copy"),
#"Renamed Columns1" = Table.RenameColumns(#"Duplicated Column",{{"Images - Copy", "ImageURLs"}})
in
#"Renamed Columns1"
So, is there any way to simply get the correct images in their correct cells whenever I refresh the table? Unfortunately, I have very limited coding knowledge so I am open to your suggestions and assistance :)
Thanks in advance!
Oandic
This shows how you can gather the links for the images into a 2d array that can be overlaid onto your data range in the sheet as the dimensions (number of rows and number of columns) match. It means you can loop the rows and columns of the array and use them to index into your data range to have the right location to then add your image from the image URL to the cell.
You can use .Top and .Left to position. Generic outline code given at bottom. You will need to size images appropriately and space rows and columns as well.
Option Explicit
Public Sub GetTable()
Dim sResponse As String, html As New HTMLDocument
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "https://royaleapi.com/clan/90R9VPP9/war/analytics", False
.send
sResponse = StrConv(.responseBody, vbUnicode)
End With
With html
.body.innerHTML = sResponse
Dim hTable As HTMLTable
Set hTable = .getElementsByTagName("table")(0)
End With
Dim numRows As Long, numColumns As Long, r As Long, c As Long, tr As Object, td As Object
numRows = hTable.getElementsByTagName("tr").Length
numColumns = hTable.getElementsByTagName("tr")(2).getElementsByTagName("td").Length
Dim arr()
ReDim arr(1 To numRows, 1 To numColumns)
For Each tr In hTable.getElementsByTagName("tr")
r = r + 1: c = 0
For Each td In tr.getElementsByTagName("td")
c = c + 1
arr(r, c) = GetImgLink(td.outerHTML)
Next
Next
[A1].Resize(numRows, numColumns) = arr '<== Just for example to see how would map to sheet
Stop
End Sub
Public Function GetImgLink(ByVal outerHTML As String) As String
On Error GoTo Errhand
GetImgLink = "https://royaleapi.com/" & Split(Split(outerHTML, "IMG class=""ui image"" src=""about:")(1), Chr$(34))(0)
Exit Function
Errhand:
Err.Clear
GetImgLink = vbNullString
End Function
Adding images and positioning (assuming data starts in A1 otherwise add an adjustment to the row, column indices of the link array you are looping.)
With ActiveSheet.Pictures.Insert(imageURL) ' <== Change to your sheet
.Left = ActiveSheet.Cells(1,1).Left '<== row and column argument to cells will come from loop position within array. Adjust if required.
.Top = ActiveSheet.Cells(1,1).Top
.Placement = 1
End With
Sample of how links map to sheet:

Resources