itration behaviour when list length = 1 - python-2.6

I'm quite new to python and am having issues with for loop behaviour. In my code I'm reading config from a file using configobj. The contents of the config file are variable and that is where I'm seeing issues.
Here's my test code:
if webconf.has_key(group):
scenario_list = webconf[group]['Scenarios']['names']
for scenario in scenario_list:
print "Scenario name = %s\n" % scenario
The "scenario_list" variable will contain any number of strings. When 'names' has multiple elements "scenario" is set to the value of each element, which is fine. When "names" has only 1 element then the loop iterates over each character of the first entry, breaking my code.
So, how do I get the for loop simply to return the value of the entry in "scenario_list" when list length is 1?
Thankyou in advance for any advice offered.

Are you using tuples rather than lists?
aTuple = (1,2,3)
aList = [1,2,3]
The big difference between tuples and lists are that tuples are immutable and lists are mutable. That is, with a list you may change the element of a list, or even add and remove elements.
The problem that you are likely encountering is related to a concept called tuple unpacking.
aList = [0] # aList is now [0]
notATuple = (0) # notATuple is now 0
# there was exactly one element in the tuple, so it was unpacked in the variable
aTuple = (0,) # aTuple is now (0,) - a tuple with one element
# the comma indicates that you wish that the tuple should not be unpacked
The only other problem I think of is that you are not putting the scenario string in a list or tuple when you have only one scenario. Python treats strings like lists (well, more like tuples) of characters. As such, if you iterate over a string you get the individual characters (the behaviour you experienced). Hence, you must put your scenario string in a list (or tuple) if want to iterate over your one string, and not its characters. Had you not been using strings you would have seen a runtime error.

Related

How to sort an array in Ruby

Persoane = []
Nume = gets
Persoane.push Nume.split(",")
puts Persoane.sort
I am trying to get an user to input carachters that get split into substrings which get inserted in an array, then the program would output the strings in alphabetical order. It doesnt seem to work and I just get the array's contents, like so:
PS C:\Users\Lenovo\Desktop\Ruby> ruby "c:\Users\Lenovo\Desktop\Ruby\ruby-test.rb"
Scrie numele la persoane
Andrei,Codrin,Bradea
Andrei
Codrin
Bradea
PS C:\Users\Lenovo\Desktop\Ruby>
you can do this :
Nume = gets
puts Nume.split(",").sort
or in 1 line
array = gets.chomp.split(",").sort
The error is because of your use of push. Let's assume that you define the constant Nume by
Nume='Andrei,Codrin,Bradea'
Then, Nume.split(',') would return the Array ['Andrei', 'Codrin', 'Bradea']. When you do a Persoane.push, the whole array is added to your array Persoane as a single element. Therefore, Persoane contains only one Element, as you can verify when you do a
p Persoane
If you sort a one-element array, the result will also be just that one element - there is nothing to sort.
What you can do is using concat instead of push. This would result in Persoane being a 3-element array which can be sorted.
I'm not sure you need use constants here
If you don't need keep user input and use it somewhere, you can just chain methods like this
persons = gets.chomp.split(",").sort
For something a little different, let's not split at all.
people = gets.scan(/[^,]+/).map(&:strip).sort
This will avoid problems like multiple commas in a row yielding empty strings. Of course, you could also avoid that with:
people = gets.split(/\,+/).map(&:strip).sort

Maintaining Ruby Set by object ID

I'm developing an algorithm in Ruby with the following properties:
It works on two objects of type Set, where each element is an Array, where all elements are of type String
Each Array involved has the same number of elements
No two arrays happen to be have the same content (when comparing with ==)
The algorithm involves many operations of moving an array from one Set to the other (or back), storing references to certain Arrays, and testing whether or not that reference is part of the Array
There is no duplication of the Arrays; all Arrays keep their object ID during all the time.
A native implementation would do something like this (to give you the idea); in practice, the arrays here have longer strings and more elements:
# Set up all Arrays involved
master=[
%w(a b c d),
%w(a b c x),
%w(u v w y),
# .... and so on
]
# Create initial sets.
x=Set.new
y=Set.new
# ....
x.add(master[0])
x.add(master[2])
y.add(master[1])
# ....
# Operating on the sets.
i=1
# ...
arr=master[i]
# Move element arr from y to x, if it is in y
if(y.member?(arr)
y.delete(arr)
x.add(arr)
end
# Do something with the sets
x.each { |arr| puts arr.pretty_print }
This would indeed work, simply because the arrays are all different in content. However, testing for membership means that y.member?(arr) tests that we don't have already an object with the same array content like arrin our Set, while it would be sufficient to verify to test that we don't have already an element with the same object_id in our Set, so I'm worried about performance. From my understanding, finding the the object id of an object is cheap, and since it is just a number, maintaining a set of numbers is more performant than maintaining a set of arrays of strings.
Therefore I could try to define my two sets as sets of object_id, and membership test would be faster. However when iterating over a Set, using the object_id to find the array itself is expensive (I would have to search ObjectSpace).
Another possibility would be to not maintain the set of arrays, but the set of indexes into my master array. My code would then be, for example,
x.add(0) # instead of x.add(master[0])
and iterating over a Set would be, i.e.
x.each { |i| puts master[i].pretty_print }
I wonder whether there is a better way - for instance that we can somehow "teach" Set.new to use object identity for maintaining its members, instead of equality.
I think you’re looking for Set#compare_by_identity, which makes the set use the object’s identity (i.e. object ID) of its contents.
x = Set.new
x.compare_by_identity

Performance: Replacing Series values with keys from a Dictionary in Python

I have a data series that contains various names of the same organizations. I want harmonize these names into a given standard using a mapping dictionary. I am currently using a nested for loop to iterate through each series element and if it is within the dictionary's values, I update the series value with the dictionary key.
# For example, corporation_series is:
0 'Corp1'
1 'Corp-1'
2 'Corp 1'
3 'Corp2'
4 'Corp--2'
dtype: object
# Dictionary is:
mapping_dict = {
'Corporation_1': ['Corp1', 'Corp-1', 'Corp 1'],
'Corporation_2': ['Corp2', 'Corp--2'],
}
# I use this logic to replace the values in the series
for index, value in corporation_series.items():
for key, list in mapping_dict.items():
if value in list:
corporation_series = corporation_series.replace(value, key)
So, if the series has a value of 'Corp1', and it exists in the dictionary's values, the logic replaces it with the corresponding key of corporations. However, it is an extremely expensive method. Could someone recommend me a better way of doing this operation? Much appreciated.
I found a solution by using python's .map function. In order to use .map, I had to invert my dictionary:
# Inverted Dict:
mapping_dict = {
'Corp1': ['Corporation_1'],
'Corp-1': ['Corporation_1'],
'Corp 1': ['Corporation_1'],
'Corp2': ['Corporation_2'],
'Corp--2':['Corporation_2'],
}
# use .map
corporation_series.map(newdict)
Instead of 5 minutes of processing, took around 5s. While this is works, I sure there are better solutions out there. Any suggestions would be most welcome.

In Ruby is there a way to get the index of an item in an array that consists of structs?

With a normal array, I can use the arrayname.find_index('whatimlookingfor') to get the position within the array.
I can't figure out how to do this when the elements of the array are Struct's.
Scenario: I have a struct that consists of an ID and the Filename. In one function I need to find within that array the ID of a different file than the one I'm currently processing. I know the other filename, so what I was hoping that I could do something like:
arrayname.filename.find_index(parsedfilename)
But this obviously fails. Without iterating through the entire array is there a way to quickly reference the index of where the match happens? Or am I out of luck because the array is a collection of structs?
index (same as find_index) takes a block in which you can code up any true/false logic for your finder. To find the index of the first item whose filename does not match parsedfilename...
found_index = items.index { |item| item.filename != parsedfilename }
Many methods which work with Arrays and Enumerables also take blocks.

Creating a Word Combinator Tool in Ruby

This is an exercise from a class on CodeLesson.com: Write a program that will accept a list of words from a user. These can either be one per line or all on a single line and delimited in some way (with commas perhaps). Then print out every combination of two words. For example, if a user were to type in book,bus,car,plane, then the output would be something like:
bookbook bookbus bookcar bookplane busbook busbus buscar busplane
carbook carbus carcar carplane planebook planebus planecar planeplane"
If you want a kickstart then use the built in Array#repeated_permutation. For doing it yourself, think of a way to loop the array; inside that loop, loop again.
You need an algorithm to obtain "permutations with repetition". Google it and you'll find many pages with explanations and algorithms. Since it's a learning assignment I won't provide an actual implementation :) but see here for instance:
Permutation with repetition without allocate memory
Now, you say none of your ideas are working. Perhaps if you add some of them to your question you can get specific tips on why they're not working and how to get your algorithm to work.
As a first idea, you could loop over each element in the array of words, and then loop over each word again inside the loop:
# Ask the user for a comma-separated input.
input = gets
# Split the input into an array, and map
# each element of the array to the same
# element, but with surrounding whitespace
# removed.
words = input.split(',').map { |w| w.strip }
# Iterate over each word.
words.each do |w1|
# For each word, iterate over
# all words once again.
words.each do |w2|
# Skip the loop if the two
# words are the same.
next if w1 == w2
puts w1 + w2
end
end
However, there is a more concise way of saying "loop through the array, and loop through the array again inside each loop": it's called repeated permutation. The method Array#repeated_permutation allows you to do this. It takes as a parameter the length of the permutation (in our case, the length is two: we iterate once over the array, and then once again inside each loop). Here's how that would look:
input = gets
words = input.split(',').map { |w| w.strip }
words.repeated_permutation(2) do |w1, w2|
next if w1 == w2
puts w1 + w2
end
Hope this helps.

Resources