I have data (names) spread out in a sheet in Excel. It is in columns A through M.
Some rows have data in every column (A-M), some rows have nothing.
I want to extract a list of every unique value (or even a list of every value, and then I can remove duplicates) in the range.
For the life of me, I cannot figure out how to do this and haven't found an example online that pulls unique values from a RANGE, and not a single column.
Any ideas? Let me know if you need a screenshot of the data for more context.
Give this macro a try:
Sub MAINevent()
Dim it As Range, r As Range, x0
With CreateObject("scripting.dictionary")
For Each it In Range("A:M").SpecialCells(2)
x0 = .Item(it.Value)
Next
Set r = Cells(1, "N").Resize(.Count, 1)
r.Value = Application.Transpose(.Keys)
End With
End Sub
You can use Go to Special (Ctrl+G -> Special) to select blanks and remove them (Ctrl+- with cells selected). Then use the formula described here to stack all your columns in one, on top of each other. Then replace formulas with values and finally, use Remove Duplicates.
Related
I need to remove duplicates from an Excel worksheet based on the values in 2 columns while taking case into account.
In the example below, Rows 1 and 2 are duplicates (Row 2 should be removed). Row 3, 4, and 5 are unique.
Row
Column A
Column B
1
Abc
Def
2
Abc
Def
3
ABC
DEF
4
ABC
DeF
5
Abc
DeF
I've done this with other datasets using Data > Remove duplicates, but since it is case-insensitive, it won't work for this.
I also found this question, which is very similar, but only identifies duplicates based on 1 column.
(How to remove duplicates that are case SENSITIVE in Excel (for 100k records or more)?)
Try this code:
Sub SubRemoveDuplicates()
'Declarations.
Dim RngData As Range
Dim RngDataToBeCompared
Dim RngCell As Range
Dim RngRow As Range
'Settings.
Set RngData = Range("A1:C6")
Set RngDataToBeCompared = Range("B2:C6")
'Covering each row of the data to be compared.
For Each RngRow In RngDataToBeCompared.Rows
CP_Rerun_For:
'Covering each cell of the given row.
For Each RngCell In RngRow.Cells
'Checking if any cell is different from the one under it.
If RngCell.Value <> RngCell.Offset(1, 0).Value Then
'If said cell has been found, skip to the next row.
GoTo CP_Next_Row
End If
Next
'Checking if the range to be targeted is within RngData.
If Not Intersect(RngRow.Offset(1, 0).EntireRow, RngData) Is Nothing Then
'Deleting the row of duplicates.
Intersect(RngRow.Offset(1, 0).EntireRow, RngData).Delete (xlShiftUp)
'Rerunning this cycle for the given row in order to catch duplicates that comes in more than 2.
GoTo CP_Rerun_For
End If
CP_Next_Row:
Next
End Sub
Note: if you are going to cover an entire column with presumably many empty cells, the macro will cover (and eventually delete) all those empty cells too. The macro can be modified so it will stop when it encounters and empty row, or to dynamically determinate the appropriate range to be covered. Otherwise it might take more time than necessary.
I don't like using macros until it's last hope.
For your situation, I would suggest adding new columns, and with function
=lower(Column A), etc. get values of column A in lower case. Then I would add one more new column and do the same for Column B.
And after that, I would use Data/Remove Duplicates (converting range to Table format first). And then I would delete unnecessary columns which were added for converting everything to lowercase.
Use this frmula to manually delete. It combines two columns on one row and compares them with the column above.
=B2&C2=B1&C1
You can then edit or filter on Col D and delete.
Ok, this has to be the easiest question ever, but I've been searching for awhile and can't figure this out. I have a very long list of values on sheet "Page1_1" (shtData) which I need to use to generate a list of unique values, along with a count of each unique value, on "Numbers". It's very simple to do manually by just copying to "Numbers" (shtNumbers) and removing duplicates, but the countif formula I use is very memory intensive, and bogs it all down. I have code to provide the unique list, but trying to get the count of each item is stumping me
Put simply: I need code to generate a list of unique values from "Page1_1" (shtData) A2:end of data, and put that list starting on "Numbers" (shtNumbers) A2 and down, then count occurrences and list the count in B2 and down.
current code:
shtData.Range("A2:A65536").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=shtNumbers.Range("A2"), Unique:=True
That code generates the list for me perfectly. I'd post what I've got for the count part, but it doesn't work at all, so I doubt it'd be helpful at all.
Thanks!
Try this:
With shtNumbers
With .Range(.Range("B2"),.Range("A2").End(xlDown).Offset(,1))
.FormulaR1C1 = "=COUNTIF(Data!C[-1],RC[-1])" 'change data to actual sheet name
End With
End With
Give this a try:
Sub SuperSimpleFrequencyTable()
Dim C As Range, A As Range, B As Range
Set A = Sheets("Page1_1").Range("A:A")
Set B = Sheets("Numbers").Range("A:A")
A.Copy B
B.RemoveDuplicates Columns:=1, Header:=xlNo
Set C = B.SpecialCells(xlCellTypeConstants).Offset(0, 1)
With C
.Formula = "=countif(Page1_1!A:A,A1)"
.Value = .Value
End With
End Sub
It will not leave formulas in the Numbers sheet.
I want to write a formula like =SUM(tab2!A:A) but instead use the column title of A which is say "count". How can I modify this to look more like: =SUM(tab2!"count")?
The reason I want to do this is because I copy and paste a spreadsheet from another source in tab2 and the column referring to "count" may be in a different column. I want the formula to give me the correct calculation as soon as I paste the new spreadsheet by automatically finding the column to sum up by title name.
I must be missing something because this seems like a very basic question and I can't find the answer anywhere...
Thanks for your help!
I like the idea of naming ranges proposed by #Doug, but if the issue is that you are dumping your data in [and you don't know in advance which column is going to be where] and would need to rename your range every time, there are other options - I suggest using OFFSET. OFFSET allows you to dynamically create a range, starting at a particular point and moving down/up / right/left for as many rows and columns as you determine.
In your case, you will need to combine that with a method for searching the columns to see which one says "Count". I am assuming that your column headings are always in row 1. If they aren't [or if they aren't always in row 2, or any row you know in advance]... you can get around that but then I'd recommend you try to make your data more uniform instead of creating unnecessary Excel workarounds.
In total your formula would look like this:
=SUM(OFFSET(A1,,MATCH("Count",1:1,0)-1,ROWS(A:A),1))
What this does is first determine which column the word "Count" is found in, in row 1. Then it subtracts 1 from that number - this now equals the number of columns to the right that it is, from column A. It uses offset to create a reference to that column, for all rows, and sums those rows together.
Check out the name manager for naming ranges :)
You didn't say whether you would consider a macro solution. If so, this may work.
If the sheet you are pasting into is Sheet2 and the sheet you want the result in is Sheet1, then this macro, if placed in the Worksheet_Activate event of Sheet1 will give you the result as soon as you click on the Sheet1 tab afetr pasting your data into Sheet2:
Private Sub Worksheet_Activate()
Dim r As Range
Dim rCol As Range
Dim rFound As Range
Dim ws As Worksheet
Dim lTotal As Long
Set ws = Sheet2
Set r = ws.Cells
Set rFound = r.Find("count")
If Not rFound Is Nothing Then
Set rCol = rFound.EntireColumn
lTotal = Application.WorksheetFunction.Sum(rCol)
End If
Cells(1, 1) = lTotal
End Sub
It does assume there is only one cell with the word "count" in it on Sheet2.
In Excel, I need to filter and display the COUNTIF & SUM of both the global range and the visible (or filtered) range.
I can already display the COUNTIF & SUM of the global range with the following code.
AtmCount = Application.WorksheetFunction.CountIf(Range("X3:X4533"), ">0")
AtmSum = Application.WorksheetFunction.Sum(Range("X3:X4533"))
I can also get the COUNT of the visible (or filtered) range as follows:
AtmCurrentCount = Range("X3:X4533").SpecialCells(xlCellTypeVisible).Count
However, this still leaves the SUM of visible (or filtered) range outstanding.
AtmCurrentSum = ???
I really stuck. Please, can somebody help me?
This will do what you want. Set visibleTotal to the appropriate data type for the total, and change the ws and rng objects to match what you have in your workbook.
Sub SumVisible()
Dim ws As Worksheet
Dim rng As Range
Dim visibleTotal As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
Set rng = ws.Range("B1:B7")
ws.AutoFilterMode = False
rng.AutoFilter field:=1, Criteria1:=5
visibleTotal = Application.WorksheetFunction.Sum(rng.SpecialCells(xlCellTypeVisible))
' print to the immediate window
Debug.Print visibleTotal
End Sub
In case you only want to sum part of the filtered range (e.g. you filter on column A but want the sum of column B), see this question and answer: Copy/Paste/Calculate Visible Cells from One Column of a Filtered Table.
If one need to COUNT the number of visible items in a filtered list, then use the SUBTOTAL function, which automatically ignores rows that are hidden by a filter.
The SUBTOTAL function can perform calculations like COUNT, SUM, MAX, MIN, AVERAGE, PRODUCT and many more (See the table below). It automatically ignores items that are not visible in a filtered list or table. This makes it ideal for showing how many items are visible in a list, the subtotal of visible rows, etc. It also provide control rows hided manually manually.
The solution to your question would be to count the number of non-blank rows visible in Column A and Column B when a filter is active, use:
AtmCurrentSum = Application.WorksheetFunction.Subtotal(109, Range("$X$3:$X$4533"))
Points to remember when you apply SUBTOTAL formula:
When function_num (First argument) is between 1-11, SUBTOTAL includes values that are hidden manually but ignore hidden by filter.
When function_num is between 101-111, SUBTOTAL excludes all kind of hidden values.
In filtered lists, SUBTOTAL always ignores values in hidden rows, regardless of function_num.
SUBTOTAL ignores other subtotals that exist in references are ignored to prevent
double-counting
SUBTOTAL only work with vertical data values arranged vertically.
In Horizontal Hidden Columns, values are always included and never ignored.
if you only want sum rather than sumif
AtmCurrentSum = application.worksheetfunction.subtotal(9, Range("X3:X4533"))
The give function Sub SumVisible() did not worked for me instead i used Subtotal function.Caution use function number 109,102,104,105 to ignores hidden values. i.e. to calculates only on visible cells.
"https://support.office.com/en-us/article/subtotal-function-7b027003-f060-4ade-9040-e478765b9939"
aSum = WorksheetFunction.Subtotal(109, CalcRange)
aCount = Application.WorksheetFunction.Subtotal(102, CalcRange)
aMax = Application.WorksheetFunction.Subtotal(104, CalcRange)
aMin = Application.WorksheetFunction.Subtotal(105, CalcRange)
If you are using Excel 2016, this will work
Sum = Application.WorksheetFunction.Subtotal(9, Range("$D2:D" & Rows(Rows.Count).End(xlUp).Row))
9 specifies that you want to sum of visible rows
My data in which I had to find sum was in D column
Hope this will help :)
I just came across this site.
https://www.techrepublic.com/blog/microsoft-office/how-to-sum-values-in-an-excel-filtered-list/
The basic formula is
x = Application.WorksheetFunction.Subtotal('code number', 'range')
The formula you want is
x = Application.WorksheetFunction.Subtotal(109, range(x, y))
This question stems off another post I had. (see Search through column in excel for specific strings where the string is random in each cell)
Using the above image as reference, I am trying to search through column B (actually over 1000 lines) using column E as the "lookup values." The end goal would be for "just" the names to be displayed in column C. The trick is all the randomly generated characters the encompass the names. Below is what I would want the datasheet to look like. A formula or module should work, but the vlookup and other lookup function I can't get to work.
For a worksheet function approach, you could enter in C3 and fill down this formula:
=LOOKUP(8^5,SEARCH(E$3:E$7,B3),E$3:E$7)
The constant 8^5=32768 is chosen to be larger than the maximum possible string length so that LOOKUP returns the last matching value. The formula returns #N/A if no string is found.
Another possibility, which may be easier to understand then assylias post initially, but also may be a bit more time consumptive (although with 1,000 rows, I don't think it will matter much) is below.
This requires that you name the range in column E as myNames (or whatever name you wish, just update the code - alternatively, you cuold just write Range("E1:E6")). Also, if you move the random values from column B, update that in the code as well.
Sub findString()
Dim celString As Range, rngString As Range, celSearch As Range, rngSearch As Range
Dim wks As Worksheet
Set wks = Sheets("Sheet1") 'change sheet reference to whatever your sheet name is
Set rngString = wks.Range("myNames")
Set rngSearch = Intersect(wks.UsedRange, wks.Range("B1").EntireColumn)
For Each celString In rngString
For Each celSearch In rngSearch
If InStr(1, celSearch.Text, celString.Value) > 0 Then
celSearch.Offset(, 1) = celString.Value
End If
Next
Next
End Sub
Since, I worked on your original question as well, I would suggest getting the counts through Siddharth's answer and then running this, or assylias's code above to get the names next to the columns. You could put a button the sheet, or just use the Macro dialog box to run the macro.