Selecting specific data from text spreadsheet on Praat - spreadsheet

Praat scripting noobie here. I'm expanding on a pre-existing piece of code right now, and it produces a bunch of tables based on a set of sound data, and here's a couple examples of what they look like when pasted into Excel:
As you can see, there are labels ascribed to different points in each sound file, and the most important ones are '%,' 'H,' & 'L'. I want to copy data from the 'tone_height' column into separate tables - 'H' tone heights in a separate 'H' table, 'L' tone heights in a separate 'L' table and so forth. Problem is, because the number of %, H, and L values are not consistent across the sound files, I'm having trouble writing an algorithm that loops through all these tables and picks up JUST the H data, for instance. This is the code I have so far:
Read TableOfReal from headerless spreadsheet file... 'directory$''name$'.means
nrows = Get number of rows
ncolumns = Get number of columns
tone_row = 0
for n from 1 to nrows
tone_height = Get value... n 12
if tone_height > 0
rowname$ = Get row label... n
Select columns where row: "5", "self[row,0] = 'H'"
endif
I was trying to tell Praat to copy column 5, and only copy the elements where the string in column 0 is 'H.' But this doesn't seem to be working - am I missing an extra step or extra conditions?

Once selected your table in Praat, try this:
Extract rows where column (text): "rowLabel", "is equal to", "H"

Related

VBA - How to refer to column names in Array?

To start, I have a scraping function that scrapes a table from a web page, and stores the data in a 2D array.
The 2D array starts from row 0 to however many rows of data are on the page, and columns 1 to however many columns there are.
Row 0 simply contains all the column names.
My ReDim:
ReDim Addresses(0 To lngTotalRecords, 1 To columns.Count) As String
I've then stored this 2D array into a scripting dictionary called dictClients, as there are multiple clients that all have their own entries for the same table on the web page.
So in my dictionary I have something like the following to refer to a particular address table for a particular client:
dictClients(1)("Addresses")
dictClients(2)("Addresses")
I now want to be able to check if a cell in a certain row contains a specific value, however the web page allows the columns to be reorganized so that:
dictClients(1)("Addresses")(1,1) 'row 1 column 1
will not always refer to the "Street Number" column. The street number column could be the following for someone else for example:
dictClients(1)("Addresses")(1,3) ' row 1 column 3
Given that these cells:
dictClients(1)("Addresses")(0,1) '(0,2) (0,3) etc.
all refer to the column's names, what's the best way for me to find the position of a particular named column?
Example: I want to get the value of the Postal Code cell in row 1, so I need to look in
dictClients(1)("Addresses")(1, POSTALCODECOLUMN),
which isn't always in the same position on the web page.
I was thinking of using the following function:
Public Function column(strArr() As String, strColumnName As String)
Dim i As Long
For i = 1 To UBound(strArr, 2)
If strArr(0, i) = strColumnName Then column = i
Next
End Function
But it just feels so lengthy calling it like:
strPostalCode =
dictClients(1)("Addresses")(1,column(dictClients(1)("Addresses"), "Postal Code")
Is there a better and easier way to do this?
Thanks.

Adding a row between cell with the same value using VBA code

Im new in VBA and want to know how can i format my table in such a way that each name in Column one do only have 1 row in between.
Some of them do have more than 1 row in between and some of them doesn't have. I just need to format then in such a way where every name on column A has 1 blank row in between. Any help would be appreciated!
Please note that i have thousands of data so manual will not work.
also i tried doing the filtering and convert them into single block. the problem with single block is that my column c do have more than 1 information which is connected to column a, .
here is an example.enter image description here

Excel Compare two sheets and update sheet 1

Okay - This has been asked multiple times, but asking again for best possible solution :
I have two excel files (not sheets). the first excel sheet is very huge and has close to 200,000 records. One of the column (Gender) is corrupted and i have to fix it.
I have a second excel file and it has only around 200 records - these have the correct value for those ones which are messed up.
for eg:
and this is the file that has correct values with only around 200 records (only the corrupted ones).
Now i need a macro , where i need to find these exact 200 records out of 200,000 records (by employee id) and replace the Gender value with correct one.
i found something similar here. but i dont want to loop 200,000 records 200 times. feels like a performance overhead.
is there a better option?
I am thinking an ideal solution would be
Loop through 200 items and use employee id per loop
Take that employee id and do a "Find" operation in the Employee id column of the master excel
If found, replace the Gender column value
would there be any other better solution? Any inputs is gladly appreciated
One way to do this through VBA is to just loop through the 200 corrections, comparing the ID with the MATCH function to find the row it belongs on, as opposed to a second loop (a second loop through 20000 would take ages like you say).
For the below sub I have copied and pasted the 200 table into columns 5:7 of the 20000 table, you can either automate this part easily enough, or just put in the correct sheet references for each part of the code.
I've also put in a checking line to make sure there IS a match for the current ID from the small table, otherwise it'd throw up an error. You could put an ELSE in front of the END IF in this error catch to highlight any ID's which weren't actually found. Here's the code, hope this method helps!
Sub replace_things()
With ActiveSheet
For x = 2 To 200 'Change this to however many is in the small table
cur = .Cells(x, 5) 'Defined cur as ID from small table
aMatch = Application.WorksheetFunction.CountIf(.Range("A:A"), cur) 'Check to see there's a match in large table
If aMatch > 0 Then ' if there's a match then...
theRow = Application.WorksheetFunction.Match(cur, .Range("A:A"), 0) 'get the row number the match is actually on
.Cells(theRow, 3) = .Cells(x, 7) 'when row is found, replace with the relevant value from col7 (col3 of small table)
End If
Next x
End With
End Sub
A super quick way, copy your CORRECT employee ID list and paste below the CORRUPT employee ID list... highlight duplicates and correct the highlighted.
Otherwise a VLOOKUP could label which ones are corrupt? basically getting a unique field from your correct list and comparing that to your corrupt list then fixing the ~200 errors.
I assume that the employee ID is a unique record so you can paste the correct ones under existing ones, sort by empID and highlight duplicates to find them easily.

Merge values in multiple columns into one

I have the following data structure:
As you see in column J, I am trying to merge data into one column from columns A & C & E & G.
I am using this formula:
=IF(ROW()<=COUNTA($A:$A);INDEX($A:$C;ROW();COLUMN(A1));INDEX($A:$C;ROW()-COUNTA($A:$A)+1;COLUMN(C1)))
and I get the values in column K as you see. Currently this formula is merging only two columns. How to modify it to merge all four columns?
And how to only get those values starting from row 5?
The column height will vary constantly: sometimes there are 10 values in column A and sometimes there are 2 values.
Either any excel formula or any VBA code will be acceptable.
There is a fairly standard method for retrieving unique values from a column but not multiple columns. To achieve the retrieval from multiple columns you need to stack multiple formulas together with the processing being passed to successive columns one the earlier formula errors out.
      
The array formula¹ in J5 is,
=IFERROR(INDEX($A$5:$A$99, MATCH(0, IF(LEN($A$5:$A$99), COUNTIF(J$4:J4, $A$5:$A$99), 1), 0)),
IFERROR(INDEX($C$5:$C$99, MATCH(0, IF(LEN($C$5:$C$99), COUNTIF(J$4:J4, $C$5:$C$99), 1), 0)),
IFERROR(INDEX($E$5:$E$99, MATCH(0, IF(LEN($E$5:$E$99), COUNTIF(J$4:J4, $E$5:$E$99), 1), 0)),
IFERROR(INDEX($G$5:$G$99, MATCH(0, IF(LEN($G$5:$G$99), COUNTIF(J$4:J4, $G$5:$G$99), 1), 0)),
""))))
I have only included columns A, C, E and G as your sample data shows only duplicates in columns B, D, F, and H.
¹ Array formulas need to be finalized with Ctrl+Shift+Enter↵. If entered correctly, Excel with wrap the formula in braces (e.g. { and }). You do not type the braces in yourself. Once entered into the first cell correctly, they can be filled or copied down or right just like any other formula. Try and reduce your full-column references to ranges more closely representing the extents of your actual data. Array formulas chew up calculation cycles logarithmically so it is good practise to narrow the referenced ranges to a minimum. See Guidelines and examples of array formulas for more information.
This answer is another way of thinking about the formulas you could use for this sort of task. It gets to the point made by #Jeeped that it is difficult to find unique values in multiple columns. My first step then is to create a single column.
If you can live with a helper column, these formulas might be a tad easier to maintain than the nested IFERROR already proposed. They are equally difficult to understand though at first glance. The other upside is that it scales nicely if the number of columns involved increases.
It is possible using CHOOSE and some INDEX math to build a single column array of a group of separated columns. The trick is that CHOOSE will join discontinuous ranges side-by-side when given an array as the selecting parameter. If this starts with columns of the same size, you can then use division and mod math to turn it into a single column.
Picture of ranges shows the four groups of data with duplicates colored red.
Formula in F2:F31 is an array formula. This is combining all of the columns into an array and then back into a single column. I selected the columns out of order just to emphasize that it is handling a discontinuous range.
=INDEX(CHOOSE({1,2,3,4}, A2:A7,C2:C7,B2:B7,D2:D7), MOD(ROW(1:30)-1, ROWS(A2:A7))+1,INT((ROW(1:30)-1)/ROWS(A2:A7))+1)
The array formula in H2 and copied down is then the standard formula for unique values. The one exception is that instead of avoiding blanks like normal, I am avoiding 0 values.
=IFERROR(INDEX(F2:F31,MATCH(0,IF(F2:F31=0,1,COUNTIF($H$1:H1,F2:F31)),0)),"")
A couple of other comments about this approach:
In the CHOOSE, I am using {1,2,3,4}. This could be replaced with TRANSPOSE(ROWS(1:4)) or whatever number of columns you have.
There is also a ROWS(A2:A7) in 2 places, this could just be 2:7 or 1:6 or whatever size was used for the column size. I used one of the data ranges so that the coloring was simplified and to emphasize it needs to match the size of the block.
And the ROW(1:30) is used for the number of total items to collect. It really only needs to be 1:24 since there are 6*4 items, but I made it big while testing.
There are definitely a couple of downsides to this approach, but it may be a good trick to keep in the toolbox. Never know when you might want to make a column out of discontinuous ranges. The largest downside is that the columns of data all need to be the same size (and of course the helper column).
This code will do what you ask:
Sub MoveData()
START_ROW = 5
START_COL = 1
STEP_COL = 2
OUTPUT_ROW = 5
OUTPUT_COL = 10
Row = START_ROW
Col = START_COL
Out_Row = OUTPUT_ROW
While Col < OUTPUT_COL
While Cells(Row, Col).Value <> ""
Cells(Out_Row, OUTPUT_COL).Value = Cells(Row, Col).Value
Out_Row = Out_Row + 1
Row = Row + 1
Wend
Row = START_ROW
Col = Col + STEP_COL
Wend
End Sub
Think you guys are making this complicated. Just pull the range of data into power query , select all the columns and unpivot them this will bring all the data into a single column

Excel countif Pulling apart a cell to do different things

Excel 2007
I have a row of cells with variation of numbers and letters (which all mean something.. not random.)
It's basically a timesheet. If they take a sick day they put in S, if they take a partial sick day they put in PS. The problem is they also put in the hours they did work too. They put it in this format: (number)/PS.
Now if it were just letters I could just do =countif(range,"S") to keep track of how many s / ps cells there are. How would I keep track if they are PS where it also has a number separated by a slash then PS.... I also still need to be able to use that number to add to a total. Is it even possible or will I have to format things different to be able to keep track of all this stuff.
Assuming this is something like what your data looks like:
A B C D E
1 1 2 S 4/PS 8
...then you could do this:
1- add a column that just totals the "S" entries with a COUNTIF function.
2- add a hidden row beneath each real data row that will copy the numerical part of the PS entries only with this function in each column:
=IF(RIGHT(B1,2)="PS",IF(ISERROR(LEFT(B1,LEN(B1)-SEARCH("/",B1)-1)),"",INT(LEFT(B1,LEN(B1)-SEARCH("/",B1)-1))),"")
3- add another column to the right that just totals the "PS" entries by summing the hidden row from step 2.
3- add another column that totals everything by just summing the data row. that will ignore the text entries automagically.
4- have a grand total column that adds those three columns up
If you don't want to see the "S" and "PS" total columns, you can of course just hide them.
So in the end, the sheet would look like this:
A B C D E F G H I J
1 1 2 S 4/PS 8 1 4 11 16
2 4 <--- hidden row
HTH...
My quick take on this is:
pass the cell value into a CSTR function, so no matter what is entered you will be working with a string.
parse the information. Look for S, PS, or any other code you deem to be valid. Use Left or Right functions if you need to look at partial string.
check for number by testing the ascii value, or trying a CINT function, which will only work if the string can be converted to integer.
If you can show a sample of your cells with variation of numbers and letters I can give you more help. Hope this works out.
-- Mike