Is there a more Pythonic way of changing `None` to `[]` than - syntax

Is there a more Pythonic way of doing this?:
if self.name2info[name]['prereqs'] is None:
self.name2info[name]['prereqs'] = []
if self.name2info[name]['optionals'] is None:
self.name2info[name]['optionals'] = []
The reason I do this is because I need to iterate over those later. They're None to begin with sometimes because that's the default value. It's my workaround to not making [] a default value.
Thanks.

If you prefer this:
self.name2info[name]['prereqs'] = self.name2info[name]['prereqs'] or []

If you can't fix the input you could do this (becomes 'better' if you need to add more):
for prop in ['prereqs', 'optionals']:
if self.name2info[name][prop] is None:
self.name2info[name][prop] = []
But replacing these values to be iterating over the empty list you just added doesn't make a whole lot of sense (unless maybe if you're appending something to this list at some point). So maybe you could just move the test for None-ness right before the iteration:
prereqs = self.name2info[name]['prereqs']
if prereqs is not None:
for prereq in prereqs:
do_stuff(prereq)
Slightly going off-topic now, but if you ever want to test if an item is iterable at all, a common (pythonic) way would be to write:
try:
my_iterable_obj = iter(my_obj)
except TypeError:
# not iterable

You could do it this way:
if not self.name2info[name]['prereqs']: self.name2info[name]['prereqs'] = []
or this way
self.name2info[name]['prereqs'] = [] if not self.name2info[name]['prereqs'] else self.name2info[name]['prereqs']

Every one of those attribute and dict lookups takes time and processing. It's Pythonic to look up self.name2info[name] just once, and then work with a temporary name bound to that dict:
rec = self.name2info[name]
for key in "prereqs optionals required elective distance".split():
if key not in rec or rec[key] is None:
rec[key] = []
Now if need to add another category, like "AP_credit", you just add that to the string of key names.

If you're iterating over them I assume they're stored in a list. In which case combining some of the above approaches would probably be best.
seq=list(map(lambda x: x or [], seq))
Is a concise way of doing it. To my knowledge conversions in map() are faster than explicit for loops because the loops are run in the underlying C code.

Related

Why variables setted inside Enum.each is not saved?

I'm trying to set a value to a variable inside a function in Enum.each, but at the end of loop, variable is empty and I don't know exactly why this behaviour.
Code:
base = "master"
candidates = ["stream", "pigeons", "maters"]
return = []
Enum.each(candidates, fn candidate ->
cond do
String.length(base) == String.length(candidate) ->
return = return ++ [candidate]
true ->
true
end
end)
IO.inspect return
At this example, return is expected to be ["stream", "maters"], but instead, it is only an empty list: []
My question is why this happens.
When dealing with languages like Elixir, it is better to think in terms of "values" and "names" instead of "variables".
The reason you cannot do what you want is that Elixir has "lexical scoping".
When you assign to a "variable", you create a new value in the inner scope. You never change the "value" of a "name" defined in the outer scope.
(you probably can get what you want with Enum.filter/2, but I'm guessing this is just an illustrative example)
EDIT:
As of today, Elixir will allow you to write something like this:
if condition_that_evals_to_false do
x = 1
else
x = 2
end
IO.inspect x # => 2
```
But this will be deprecated in Elixir 1.3
Any reason why you don't just filter?
Anyways it seems like you're trying to mutate the value of return which is not possible with Elixir.
base = "master"
candidates = ["stream", "pigeon", "maters"]
result = Enum.filter(candidates, fn(candidate) ->
length(candidate) == length(base)
end
IO.inspect result
Edit: I'd also like to add that based on your logic, all of the candidates would be returned
Not sure, since I've never worked with the language, but a couple things spring to mind:
String.length(base) == String.length(candidate) can be equivalent to true, which is already a pattern in your set.
It could also be a scope issue with the return variable. It could be that the local return is hiding the global return. You could check this by outputting return every iteration. Each iteration the return should contain a single entry.
This is a bug. From Elixir's documentation:
Note: due to a bug in the 0.12.x series, cond‘s conditions actually
leak bindings to the surrounding scope. This should be fixed in
0.13.1.
You should use filtering like #{Christopher Yammine} suggested.

Ruby String#unpack

I have a packed string of 3 strings that is composed in a way so that I have an integer, specifying the byte length of the next item and then that item's bytes and then the next item's bytesize, etc. as if somebody did:
[a.bytesize, a, b.bytesize, b, c.bytesize, c].pack("na*na*na*")
How can I properly unpack that in a simple manner? The Perl solution to this problem was:
my($a, $b, $c) = unpack("(n/a*)3", $data)
For ruby, which apparently doesn't support '/' and parentheses in unpack, I'm using something like:
vals = []
3.times do
size = data.unpack("n").first
data.slice!(0, 2)
vals << data.unpack("a#{size}").first
data.slice!(0, size)
end
Is there an easier way to this?
IMHO it is not as easy as in PERL, but this is some solution I can suggest.
unpacked = []
a, b, c = *unpacked << data.slice!(0, data.slice!(0, 2).unpack('S>').first) \
until data.empty?
I don't see a way to do this as easily as the Perl solution (and agree it would be good to file a feature request to get that added in Ruby's pack/unpack implementation), but I could at least provide the solution in fewer lines if that helps:
vals = []
until data.empty?
vals << data.slice!(0, data.slice!(0,2).unpack('n').first.to_i).unpack("a*").first
end
If you need any serious binary data processing, there's a gem for it:
http://bindata.rubyforge.org/
I think you should use it, instead of forging unpacks un running loops.
You can of course file a feature request and wait for it to be implemented,
but I suggest you use bindata gem instead, which is a much more robust solution IMO.

Ruby: how to find the next match in an array

I have to search an item in an array and return the value of the next item. Example:
a = ['abc.df','-f','test.h']
i = a.find_index{|x| x=~/-f/}
puts a[i+1]
Is there any better way other than working with index?
A classical functional approach uses no indexes (xs.each_cons(2) -> pairwise combinations of xs):
xs = ['abc.df', '-f', 'test.h']
(xs.each_cons(2).detect { |x, y| x =~ /-f/ } || []).last
#=> "test.h"
Using Enumerable#map_detect simplifies it a litte bit more:
xs.each_cons(2).map_detect { |x, y| y if x =~ /-f/ }
#=> "test.h"
The reason something like array.find{something}.next doesn't exist is that it's an array rather than a linked list. Each item is just it's own value; it doesn't have a concept of "the item after me".
#tokland gives a good solution by iterating over the array with each pair of consecutive items, so that when the first item matches, you have your second item handy. There are strong arguments to be made for the functional style, to be sure. Your version is shorter, though, and I'd argue that yours is also more quickly and easily understood at a glance.
If the issue is that you're using it a lot and want something cleaner and more to the point, then of course you could just add it as a singleton method to a:
def a.find_after(&test)
self[find_index(&test).next]
end
Then
a.find_after{|x| x=~/-f/}
is a clear way to find the next item after the first match.
All of that said, I think #BenjaminCox makes the best point about what appears to be your actual goal. If you're parsing command line options, there are libraries that do that well.
I don't know of a cleaner way to do that specific operation. However, it sure looks like you're trying to parse command-line arguments. If so, I'd recommend using the built-in OptionParser module - it'll save a ton of time and hair-pulling trying to parse them yourself.
This article explains how it works.
Your solution working with indexes is fine, as others have commented. You could use Enumerable#drop_while to get an array from your match on and take the second element of that:
a = ['abc.df','-f','test.h']
f_arg = a.drop_while { |e| e !~ /-f/ }[1]

Erlang binary matching efficiency

What would be the difference between matching like:
fun(Binary) ->
[Value, Rest] = binary:split(Binary, <<101>>)
end
and
fun(Binary) ->
[Value, <<Rest/binary>>] = binary:split(Binary, <<101>>)
end
I am thinking that one may simply increment a counter as it traverses the binary and keep the sub binary pointer and the other will copy a new binary. Any ideas?
I can think of pattern matching in two ways.
Method 1:
[A,B] = [<<"abcd">>,<<"fghi">>]
Method 2:
[A, <<B/binary>>] = [<<"abcd">>,<<"fghi">>]
Unless you need to make it sure B is binary, Method 2 will take it longer, few micro seconds, because it's not just assigning <<"fghi">> to B, but also make it sure it is bianary.
However if you need more parsing than method 2, you can go further, which method 1 can't do.
[A, <<B:8, Rest/binary>>] = [<<"abcd">>,<<"fghi">>].
I think you could test it by timer module's tc/N function.

How to copy a dict and modify it in one line of code

Very often I need to create dicts that differ one from another by an item or two. Here is what I usually do:
setup1 = {'param1': val1,
'param2': val2,
'param3': val3,
'param4': val4,
'paramN': valN}
setup2 = copy.deepcopy(dict(setup1))
setup2.update({'param1': val10,
'param2': val20})
The fact that there is a point in the program at which setup2 is an identical copy of setup1 makes me nervous, as I'm afraid that at some point of the program life the two lines might get separated, which is a slippery slope towards too many bugs.
Ideally I would like to be able to complete this action in a single line of code (something like this):
setup2 = dict(setup1).merge({'param1': val10,
'param2': val20})
Of course, I can use semicolon to squeeze two commands into one physical line, but this looks pretty ugly to me. Are there other options?
The simplest way in my opinion is something like this:
new_dict = {**old_dict, 'changed_val': value, **other_new_vals_as_dict}
You could use keyword arguments in the dictionary constructor for your updates
new = dict(old, a=1, b=2, c=3)
# You can also unpack your modifications
new = dict(old, **mods)
This is equivalent to:
new = old.copy()
new.update({"a": 1, "b": 2, "c": 3})
Source
Notes
dict.copy() creates a shallow copy.
All keys need to be strings since they are passed as keyword arguments.
setup2 = dict(setup1.items() + {'param1': val10, 'param2': val20}.items())
This way if new keys do not exist in setup1 they get added, otherwise they replace the old key/value pairs.
Solution
Build a function for that.
Your intention would be clearer when you use it in the code, and you can handle complicated decisions (e.g., deep versus shallow copy) in a single place.
def copy_dict(source_dict, diffs):
"""Returns a copy of source_dict, updated with the new key-value
pairs in diffs."""
result=dict(source_dict) # Shallow copy, see addendum below
result.update(diffs)
return result
And now the copy is atomic, assuming no threads involved:
setup2=copy_dict(setup1, {'param1': val10, 'param2': val20})
Addendum - deep copy
For primitives (integers and strings), there is no need for deep copy:
>>> d1={1:'s', 2:'g', 3:'c'}
>>> d2=dict(d1)
>>> d1[1]='a'
>>> d1
{1: 'a', 2: 'g', 3: 'c'}
>>> d2
{1: 's', 2: 'g', 3: 'c'}
If you need a deep copy, use the copy module:
result=copy.deepcopy(source_dict) # Deep copy
instead of:
result=dict(setup1) # Shallow copy
Make sure all the objects in your dictionary supports deep copy (any object that can be pickled should do).
setup2 = dict((k, {'param1': val10, 'param2': val20}.get(k, v))
for k, v in setup1.iteritems())
This only works if all keys of the update dictionary are already contained in setup1.
If all your keys are strings, you can also do
setup2 = dict(setup1, param1=val10, param2=val20)
If you just need to create a new dict with items from more than one dict, you can use:
dict(a.items() + b.items())
If both "a" and "b" have some same key, the result will have the value from b.
If you're using Python 3, the concatenation won't work, but you can do the same by freezing the generators to lists, or by using the itertools.chain function.
This is an extension to the nice answer posted by Adam Matan:
def copy_dict(d, diffs={}, **kwargs):
res = dict(d)
res.update(diffs)
res.update(kwargs)
return res
The only difference is the addition of kwargs.
Now one can write
setup2 = copy_dict(setup1, {'param1': val10, 'param2': val20})
or
setup2 = copy_dict(setup1, param1=val10, param2=val20)
From Python 3.9, you can use the pipe command (e.g. first_dic | second_dic) for merging dictionary; it can also be used for returning a new updated dictionary by passing the original dictionary first, and the update as a second dictionary:
setup2 = setup1 | {'param1': val10, 'param2': val20}
You can write your own class using UserDict wrapper, and simply add dicts like
# setup1 is of Dict type (see below)
setup2 = setup1 + {'param1': val10}
All you have to do is
Define a new class using UserDict as base class
Implement __add__ method for it.
Something like :
class Dict(dict):
def __add__(self, _dict):
if isinstance(_dict, dict):
tmpdict = Dict(self)
tmpdict.update(_dict)
return tmpdict
else:
raise TypeError
def __radd__(self, _dict):
return Dict.__add__(self, _dict)
I like this line (after from itertools import chain):
d3 = dict(chain(d1.items(), d2.items()))
(Thanks for juanpa.arrivillaga for the improvement!)
Some good answers above. I came here because I had the same issue. Thought the function solution was the most elegant since the question mentioned "often"
def variant(common, diffs):
"""Create a new dict as a variant of an old one
"""
temp = common.copy()
temp.update(diffs)
return temp
to call it you simply use:
PTX130 = variant(PTX100, {'PA_r': 0.25, 'TX_CAP': 4.2E-10})
which for me says that the PTX130 is a variant of the PTX100 with different PA resistance and TX capacitance.

Resources