populating a wxGrid from an array using a range for rows - loops

This should be simple but I'm tearing my hair out trying to make it work:
I want to populate a grid with the values from an sqlite query.
rowNum = 3 # This is from a 'select count' query
row_num = range(rowNum) # This gives me [0, 1, 2]
tbl = [('apple', 'fruit'), ('bacon', 'meat'), ('rose', 'flower')] # from another query
for row in tbl:
cells = row[0:2]
for i in range(len(cells)):
self.mygrid.SetCellValue(row_num, i, str(cells[i]))
This tells me 'overload 1: argument 1 has unexpected type 'list'
for a in row_num:
for row in tbl:
cells = row[0:2]
for i in range(len(cells)):
self.mygrid.SetCellValue(row_num[a], i, str(cells[i]))
This populates three rows of the grid with 'rose' in col 1 and 'flower' in col2
I know this is a simple iteration problem but my mind doesn't see it.

In your first code block you do SetCellValue(row_num... where row_num is always [0, 1, 2].
In the second, you actually have 3 cycles, the innermost always writes all rows from tbl into the same row (row_num[a]), and the last one stays.
How about this:
for (row_idx, row) in enumerate(tbl):
for (col_idx, col) in enumerate(row[0:2]):
self.mygrid.SetCellValue(row_idx, col_idx, str(col))

Related

Finding adjacent column values from the last non-null row of a certain column

Is there a simple in-built function to select adjacent values from the last non-null row for a certain column?
In the below example the last non-null value in Column A is "E", and I'd like to select the corresponding value "13" from the next column.
Try:
=VLOOKUP(INDEX(A:A,MAX((A:A<>"")*(ROW(A:A)))),A1:B,2,0)
Refer Selecting the last value of a column. There are 22 answers toi choose from.
I like =INDEX(I:I;MAX((I:I<>"")*(ROW(I:I)))). It is one of the shortest and it copes with blank rows.
Add VLOOKUP and you can get the value on the adjacent columns.
try:
=QUERY(A3:B, "select B where A !='' offset "&COUNTA(A3:A)-1)
or:
=ARRAYFORMULA(VLOOKUP(INDIRECT("A"&MAX(IF(A2:A="",,ROW(A2:A)))), A2:B, 2, 0))
or:
=ARRAYFORMULA(VLOOKUP(INDEX(QUERY({A2:A, ROW(A2:A)},
"where Col1 !='' order by Col2 desc"), 1, 1), A2:B, 2, 0))
=indirect("B" & max(ARRAYFORMULA(row(A1:A)*if(A1:A="",0,1))),true)
or
=indirect("B" & arrayformula(max(if(A1:A<>"",row(A1:A),0))),true)
or with offset
=offset(B1,ARRAYFORMULA(MAX(if(A:A="",0,row(A:A))))-1,0)

How can I use an array as input for FILTER function in Google Spreadsheet?

So this might be trivial, but it's kinda hard to ask. I'd like to FILTER a range based other FILTER results.
I'll try to explain from inside out (related to image below):
I use filter to find all names for given id (the results are joined in column B). This works fine and returns an array of values. This is the inner FILTER.
I want to use this array of names to find all values for them using another outer FILTER.
In other words: Find maximum value for all names for given id.
Here is what I've figured:
=MAX(FILTER(J:J, CONTAINS???(FILTER(G:G, F:F = A2), I:I)))
^--- imaginary function returning TRUE for every value in I
that is contained in the array
=MAX(FILTER(J:J, I:I = FILTER(G:G, F:F = A2)))
^--- equal does not work here when filter returns more than 1 value
=MAX(FILTER(J:J, REGEXMATCH(JOIN(",", FILTER(G:G, F:F = A2)), I:I)))
^--- this approach WORKS but is ineffective and slow on 10k+ cells
https://docs.google.com/spreadsheets/d/1k5lOUYMLebkmU7X2SLmzWGiDAVR3u3CSAF3dYZ_VnKE
I hope to find better CONTAINS function then the REGEXMATCH/JOIN combo, or to do the task using other approach.
try this in A2 cell (after you delete everything in A2:C range):
=SORTN(SORT({INDIRECT("F2:F"&COUNTA(F2:F)+1),
TRANSPOSE(SUBSTITUTE(TRIM(QUERY(QUERY(QUERY({F2:G},
"select max(Col2) group by Col2 pivot Col1"), "offset 1"),,999^99)), " ", ",")),
VLOOKUP(INDIRECT("G2:G"&COUNTA(F2:F)+1), I2:J, 2, 0)}, 1, 1, 3, 0), 999^99, 2, 1, 1)

Counting rows in a table based on multiple array criterias

I am trying to count rows in a table based on multiple criteria in different columns of that table. The criteria are not directly in the formula though; they are arrays which I would like to refer to (and not list them in the formula directly).
Range table example:
Group Status
a 1
b 4
b 6
c 4
a 6
d 5
d 4
a 2
b 2
d 3
b 2
c 1
c 2
c 1
a 4
b 3
Criteria/arrays example:
group
a
b
status
1
2
3
I am able to do this if i only have one array search through a range (1 column) in that table:
{=SUM(COUNTIFS(data[Group],group[group]))}
Returns "9" as expected (=sum of rows in the group column of the data table which match any values in group[group])
But if I add a second different range and a different array I get an incorrect result:
{=SUM(COUNTIFS(data[Group],group[group], data[Status],status[status]))}
Returns "3" but should return "5" (=sum of rows which have 1, 2 or 3 in the status column and a or b in the group column)
I searched and googled for various ideas related to using sumproduct or defining arrays within the formula instead of classifying the whole formula as an array but I was not able to get expected results via those means.
Thank you for your help.
Because your group and status criteria are a different number of values (2 values for group, but 3 values for status), I'm not sure you can do this in a single formula. Best way I know of to do this would be to use a helper column (which can be hidden if preferred).
Put this array formula in a helper column and copy down the length of your data (array formulas must be confirmed with Ctrl+Shift+Enter):
=AND(OR(data[#Group]=group[group]),OR(data[#Status]=status[status]))
And then get the count with: =COUNTIF(helpercolumn,TRUE)
You could use a slightly different approach, using Power Query / Power Pivot.
Name your tables Data, Group and Status, then create the following query, named Filtered Data:
let
tbData = Excel.CurrentWorkbook(){[Name="Data"]}[Content],
tbGroup = Excel.CurrentWorkbook(){[Name="Group"]}[Content],
tbStatus = Excel.CurrentWorkbook(){[Name="Status"]}[Content],
#"Merged Group" = Table.NestedJoin(tbData,{"Group"},tbGroup,{"Group"},"tbGroup",JoinKind.Inner),
#"Merged Status" = Table.NestedJoin(#"Merged Group",{"Status"},tbStatus,{"Status"},"Merged Status",JoinKind.Inner),
#"Removed Columns" = Table.RemoveColumns(#"Merged Status",{"tbGroup", "Merged Status"}),
#"Changed Type" = Table.TransformColumnTypes(#"Removed Columns",{{"Status", type number}})
in
#"Changed Type"
Load To as connection only, and tick Load to Data Model
Now create a DAX measure:
Status Sum:=SUM ( 'Filtered Data'[Status] )
You can then use the following formula on your worksheet, to get the Sum of Status values, for rows matching the criteria specified in the Group and Status tables:
=CUBEVALUE("ThisWorkbookDataModel","[Measures].[Status Sum]")
Simply refresh the data connection to update the value.

Replace first 4 rows with values from rows 5:8 arcpy

I am trying to replace the values in the first 4 rows of a attribute table with the row values from the next 4 rows 5:8 in an attribute table using arcpy.da.UpdateCursor. Is there a simple way to index rows 1:4 (all columns) and replace with values from rows 5:8.
Here is my code thus far:
targetFC = r"D:\ZOC\POLYPGDIS_MASTER_1.shp"
dsc = arcpy.Describe(sourceFC)
fields = dsc.fields
# List all field names except the OID field
fieldnames = [field.name for field in fields if field.name != dsc.OIDFieldName]
with arcpy.da.UpdateCursor(targetFC, fieldnames) as cursor:
for row in cursor:
row[1:4] = row[5:8]
cursor.updateRow(row)
Thanks
I think the easiest way would be to load the data into a list.
Note if you are working with a RDBMS the row order is not certain so this probably would not work unless you sorted by something.
eight_rows = []
k = 0
with arcpy.da.SearchCursor(targetFC, fieldnames) as rows:
for row in rows:
eight_rows.append(row)
k += 1
if k == 8: break
k = 5
with arcpy.da.UpdateCursor(targetFC, fieldnames) as rows:
for row in rows:
row = eight_rows[k]
k += 1
rows.updateRow(row)
if k == 8: break

TSQL - How to prevent optimisation in this query

I have a query analogous to:
update x
set x.y = (
select sum(x2.y)
from mytable x2
where x2.y < x.y
)
from mytable x
the point being, I'm iterating over rows and updating a field based on a subquery over those fields which are changing.
What I'm seeing is the subquery is being executed for each row before any updates occur, so the changed values for each row are not being picked up.
How can I force the subquery to be re-evaluated for each row of the update?
Is there a suitable table hint or something?
As an aside, I was doing the below and it did work, however since modifying my query somewhat (for logic purposes, not to try and solve this issue) this trick no longer works :(
declare #temp int
update x
set #temp = (
select sum(x2.y)
from mytable x2
where x2.y < x.y
),
x.y = #temp
from mytable x
I'm not particularly concerned about performance, this is a background task run over a few rows
It looks like task is incorrect or other rules should apply.
Let's see on example. Let's say you have values 4, 1, 2, 3, 1, 2
Sql will update rows based on original values. I.e. during single update statement newly calculated values is NOT mixing with original values:
-- only original values used
4 -> 9 (1+2+3+1+2)
1 -> null
2 -> 2 (1+1)
3 -> 6 (1+2+1+2)
1 -> null
2 -> 2 (1+1)
Based on your request you wants that update of each rows will count newly calculated values. (Note, that SQL does not guarantees the sequence in which rows will be processed.)
Let's do this calculation by processing rows from top to bottom:
-- from top
4 -> 9 (1+2+3+1+2)
1 -> null
2 -> 1 (1)
3 -> 4 (1+1+2)
1 -> null
2 -> 1 (1)
Do the same in other sequence - from bottom to top:
-- from bottom
4 -> 3 (2+1)
1 -> null
2 -> 1 (1)
3 -> 5 (2+2+1)
1 -> null
2 -> 2 (1+1)
How you can see your expected result is inconsistent. To make it right you need to correct the calculation rule - for instance define strong sequence of the rows to process (date, id, ...)
Also, if you want to do some recursive processing look at the common_table_expression:
http://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

Resources