Pythonic way to increment and assign ids from dictionary - dictionary

This seems to be a pretty common pattern:
for row in reader:
c1=row[0]
if ids.has_key(c1):
id1=ids.get(c1)
else:
currid+=1
id1=currid
ids[c1]=currid
I want to know if there is a better way to achieve this. As far as single line if statements go, I could do this much:
id1=ids.get(c1) if ids.has_key(c1) else currid+1
But then I'm stuck with incrementing currid and sticking if the else case was executed and sticking c->id1 into the dictionary if the if condition passed.

If the ids start from 0:
for row in reader:
id1 = ids.setdefault(row[0], len(ids))
(Aside: has_key is considered deprecated. Use x in d instead of d.has_key(x).)

If you don't mind changing how ids is defined, then you could go with this (all in the standard library):
ids = collections.defaultdict (itertools.count ().next)
Usage is then very simple:
print (ids["lol"])

currid += c1 not in ids
id1 = ids.setdefault(c1, currid)

Use this instead:
id1 = ids.get(cl, currid + 1)

A bit more pythonyc, with the same semantics:
for row in reader:
c1 = row[0]
if c1 not in ids:
currid += 1
ids[c1] = currid
id1 = ids[c1]

Related

Progess 4GL - How to filter multiple records using AND operator in one table field?

I want to check and filter only if the table has value1 = 005 and value1 = 009. But it seems below query is not helping me. I dont know where I am making mistakes. Kindly help to solve this. Note - I cannot use where not as it may have many different value stored in value1 field
DEFINE TEMP-TABLE test NO-UNDO
FIELD value1 AS CHARACTER
.
EMPTY TEMP-TABLE test.
CREATE test.
ASSIGN
value1 = "005".
CREATE test.
ASSIGN
value1 = "009".
CREATE test.
ASSIGN
value1 = "001".
FOR EACH test NO-LOCK
WHERE value1 <> ""
AND (value1 = "005" AND value1 = "009")
:
MESSAGE YES.
END.
You can use can-find
if can-find(first test WHERE value1 = "005")
AND can-find(first test WHERE value1 = "009")
then message yes.
It is safest to always use can-find(first if you're looking for a non-unique value
It looks like you're looking for an OR ooperation, rather than AND.
If you want to check if both records are present you could do :
DEFINE VARIABLE isPresent005 AS LOGICAL NO-UNDO.
DEFINE VARIABLE isPresent009 AS LOGICAL NO-UNDO.
DEFINE VARIABLE bothPresents AS LOGICAL NO-UNDO.
FIND FIRST test WHERE test.value1 = "005" NO-LOCK NO-ERROR.
isPresent005 = AVAIL test.
FIND FIRST test WHERE test.value1 = "009" NO-LOCK NO-ERROR.
isPresent009 = AVAIL test.
bothPresents = isPresent005 AND isPresent009.
But, if you only want to get these 2 records, you should use OR :
FOR EACH test WHERE test.value1 = "005" OR test.value1 = "009" NO-LOCK :
/*do stuff*/
END.
Another option if you are, maybe, looking for some additional fields might look something like this:
define buffer test005 for test.
define buffer test009 for test.
for each test005 no-lock where test005.customer = 1 and test005.value1 = "005",
each test009 no-lock where test009.customer = 1 and test009.value1 = "009":
display test005.customer.
end.
Use OR instead of AND to search the records...
This will return records if value1 = 005 OR value1 = 009.
FOR EACH test NO-LOCK
WHERE value1 <> ""
AND (value1 = "005" OR value1 = "009")
:
MESSAGE YES.
END.
Is not possible to search using your way, because value1 cannot be two values at once, it's always one OR another.

How to count equal values of the same element name [xQuery]

Here is an example:
`
<bracketQualifier>
<bracketSequenceNumber>1</bracketSequenceNumber>
</bracketQualifier>
<bracketQualifier>
<bracketSequenceNumber>1</bracketSequenceNumber>
</bracketQualifier>
<bracketQualifier>
<bracketSequenceNumber>1</bracketSequenceNumber>
</bracketQualifier>
`
What i need to do is if bracketSequenceNumber holds the same value trow an exception.
Number of elements is N there can be more than 3. How can i achieve this using xquery.
I tried something like this without success and i cant say i understand xQuery completley:
`
let $count := ( for $bracketSequenceNumber in $bracketQualifier/bracketSequenceNumber return count(bracketQualifier[#bracketSequenceNumber = $bracketSequenceNumber ])) return
if($GDSN_PriceSyncPriceSegmentTM/value ='250' and $count >= 1) then something
`
You can use
if (count(//bracketSequenceNumber)
!= count(distinct-values(//bracketSequenceNumber) then ...
If you actually want to find the duplicates, use group by in XQuery 3.1 to process each group of equal values and test whether the group size is 2 or more.

CASE statement not Defining a Column Correctly Snowflake

I have a query in following format, used to perform COALESCE as well as define a new column using CASE statement.
SELECT ....
COALESCE(mm1,'missing') AS mm1,
COALESCE(mm2,'missing') AS mm2,
CASE WHEN mm1='false' AND mm2='false' THEN 'No-Proxy'
WHEN mm1 IN ('false','missing') AND mm2='true' THEN 'Good-Proxy'
WHEN mm1 ='true' AND mm2 IN ('false','missing') THEN 'Bad-Proxy'
WHEN ((mm1='true' AND mm2='true') OR (mm1='missing' AND mm2='missing')
OR (mm1='false' AND mm2='missing') OR (mm1='missing' AND mm2='false')) THEN 'Unknown'
END AS Proxy_Type,
As seen above when both mm1 and mm2 are originally NULL, we need to put value as Unknown for Proxy_Type. But when we run the query, we get unexpected output. Plz see screenshot.
Kindly advise on how to fix it.
It seems that "inline/lateral column aliasing" does not allow to "override" column at the same level:
CREATE OR REPLACE TABLE t
AS SELECT NULL AS mm1, NULL AS mm2;
Option 1: Using different column alias
SELECT
COALESCE(mm1,'missing') AS mm1_,
COALESCE(mm2,'missing') AS mm2_,
CASE WHEN mm1_='false' AND mm2_='false' THEN 'No-Proxy'
WHEN mm1_ IN ('false','missing') AND mm2_='true' THEN 'Good-Proxy'
WHEN mm1_ ='true' AND mm2_ IN ('false','missing') THEN 'Bad-Proxy'
WHEN ((mm1_='true' AND mm2_='true') OR (mm1_='missing' AND mm2_='missing')
OR (mm1_='false' AND mm2_='missing')
OR (mm1_='missing' AND mm2_='false')) THEN 'Unknown'
END AS Proxy_Type
FROM t;
-- MM1_ MM2_ PROXY_TYPE
--missing missing Unknown
Option 2: LATERAL JOIN and prefixing with subquery alias:
SELECT -- t.mm1, t.mm2,
s.mm1, s.mm2,
CASE WHEN s.mm1='false' AND s.mm2='false' THEN 'No-Proxy'
WHEN s.mm1 IN ('false','missing') AND s.mm2='true' THEN 'Good-Proxy'
WHEN s.mm1 ='true' AND s.mm2 IN ('false','missing') THEN 'Bad-Proxy'
WHEN ((s.mm1='true' AND s.mm2='true') OR (s.mm1='missing' AND s.mm2='missing')
OR (s.mm1='false' AND s.mm2='missing')
OR (s.mm1='missing' AND s.mm2='false')) THEN 'Unknown'
END AS Proxy_Type
FROM t,
LATERAL(SELECT COALESCE(t.mm1,'missing') AS mm1,COALESCE(t.mm2,'missing') AS mm2) s;
-- MM1 MM2 PROXY_TYPE
--missing missing Unknown
The ideal situation would be if we had additional keyword to distinguish between original column and calculated expression, kind of SAS - calculated.
SELECT
col,
col+10 AS col,
col,
calculated col
FROM t;
-- output
t.col/expression/t.col/expression
I’m guessing you are trying to use the re-defined values of mm1/mm2 in your case statement? If so then SQL doesn’t work like that, values don’t change within the same select statement so m1/m2 will have their starting values wherever they are referenced in the select statement.
One way round this is to use something like this:
COALESCE(mm1,'missing') AS mm1,
COALESCE(mm2,'missing') AS mm2,
CASE WHEN COALESCE(mm1,'missing') ='false' …

Count characters in a string without spaces

I am trying to count the characters without the spaces.
Here is my code:
word = 'Ricardo Cadenas'
def string_lenght(word):
count = 0
for char in word:
count = count + 1
return count - word.count('')
print(string_lenght(word))
my out put is-1 ??? any ideas?
You have a typo. I think you meant to put word.count(' ') but you put word.count('') (no space.)
Also instead of looping to calculate count, you can initialize count = len(word).
Correct, changing “” to “ “ should do the trick!

Select Top 1 From a Table For Each row in another Table

I am just starting to work with openedge and I need to join information from two tables but I just need the first row from the second one.
Basically I need to do a typical SQL Cross Apply but in progress. I look in the documentation and the Statement FETCH FIRST 10 ROWS ONLY only in OpenEdge 11.
My query is:
SELECT * FROM la_of PUB.la_ofart ON la_of.empr_cod = la_ofart.empr_cod
AND la_of.Cod_Ordf = la_ofart.Cod_Ordf
AND la_of.Num_ordex = la_ofart.Num_ordex AND la_of.Num_partida = la_ofart.Num_partida
CROSS APPLY (
SELECT TOP 1 ofart.Cod_Ordf AS Cod_Ordf_ofart ,
ofart.Num_ordex AS Num_ordex_ofart
FROM la_ofart AS ofart
WHERE ofart.empr_cod = la_ofart.empr_cod
AND ofart.Num_partida = la_ofart.Num_partida
AND la_ofart.doc1_num = ofart.doc1_num
AND la_ofart.doc2_linha = ofart.doc2_linha
ORDER BY ofart.Cod_Ordf DESC) ofart
I am using SSMS to extract data from OE10 using an ODBC connector and querying to OE using OpenQuery.
Thanks for all help.
If I correctly understood your question, maybe you can use something like this. Maybe this isn't the best solution for your problem, but may suit your needs.
DEF BUFFER ofart FOR la_ofart.
DEF TEMP-TABLE tt-ofart NO-UNDO LIKE ofart
FIELD seq AS INT
INDEX ch-seq
seq.
DEF VAR i-count AS INT NO-UNDO.
EMPTY TEMP-TABLE tt-ofart.
blk:
FOR EACH la_ofart NO-LOCK,
EACH la_of NO-LOCK
WHERE la_of.empr_cod = la_ofart.empr_cod
AND la_of.Cod_Ordf = la_ofart.Cod_Ordf
AND la_of.Num_ordex = la_ofart.Num_ordex
AND la_of.Num_partida = la_ofart.Num_partida,
EACH ofart NO-LOCK
WHERE ofart.empr_cod = la_ofart.empr_cod
AND ofart.Num_partida = la_ofart.Num_partida
AND ofart.doc1_num = la_ofart.doc1_num
AND ofart.doc2_linha = la_ofart.doc2_linha
BREAK BY ofart.Cod_Ordf DESCENDING:
ASSIGN i-count = i-count + 1.
CREATE tt-ofart.
BUFFER-COPY ofart TO tt-ofart
ASSIGN ofart.seq = i-count.
IF i-count >= 10 THEN
LEAVE blk.
END.
FOR EACH tt-ofart USE-INDEX seq:
DISP tt-ofart WITH SCROLLABLE 1 COL 1 DOWN NO-ERROR.
END.

Resources