Showing posts with label algorithms. Show all posts
Showing posts with label algorithms. Show all posts

Tuesday, January 29, 2019

Daily Coding Problem #69: A functional programming solution


- By Vasudev Ram - Online Python training / SQL training / Linux training




Stock reduction image attribution

Hi, readers,

I subscribed to the mailing list of the Daily Coding Problem site site a while ago. It's a useful site. Their modus operandi is to send you one programming problem per day, described in English. You try to solve them, in any programming language of your choice. (They say that some of the questions were asked by companies like Google, Facebook, Amazon, Microsoft, Netflix, etc.) Something like Rosetta Code.
The idea is that you can use this to practice and improve your programming and algorithm development skills.

I haven't been attempting to solve every problem I get in email from them, as of now. I just try one now and then. Hope to attempt more later.

Daily Coding Problem #69 is one that I tried, and solved, using a functional programming approach.

This is the problem statement (taken from the email I got from them):

Daily Coding Problem: Problem #69
To: vasudevram@gmail.com
Good morning! Here's your coding interview problem for today.

This problem was asked by Facebook.

Given a list of integers, return the largest product that can be made by multiplying any three integers.

For example, if the list is [-10, -10, 5, 2], we should return 500, since that's -10 * -10 * 5.

You can assume the list has at least three integers.

And here is my functional-style solution below (actually, two variants on a solution). For this post, I've used a slightly different format than what I usually use - instead of alternating code and (text) explanations, I've put all the explanations in the code, as comments - sort of like literate programming.
# daily_coding_problem_069.py
# Problem source: https://dailycodingproblem.com
# Solution created by Vasudev Ram
# Website: https://vasudevram.github.io
# Copyright 2019 Vasudev Ram
# Blog: https://jugad2.blogspot.com
# Python posts: https://jugad2.blogspot.com/search/label/python
# Product store: https://gumroad.com/vasudevram
# Twitter: https://mobile.twitter.com/vasudevram
# LinkedIn: https://linkedin.com/in.vasudevram

"""
Daily Coding Problem: Problem #69

This problem was asked by Facebook.

Given a list of integers, return the largest product that can be made 
by multiplying any three integers.

For example, if the list is [-10, -10, 5, 2], we should return 500, 
since that's -10 * -10 * 5.

You can assume the list has at least three integers.
"""

from __future__ import print_function

try:
    reduce
except NameError as ne:
    from functools import reduce

from itertools import combinations

# Create a list with a few numbers.
lis = range(1, 6)
print()
print("lis:", lis)

# First, print the combinations iterator object.
print("combinations(lis, 3):", combinations(lis, 3))
# Next, print the combinations themselves.
print("list(combinations(lis, 3)):\n" + \
    "\n".join(str(item) for item in list(combinations(lis, 3))))
print()

# Then define a function that takes an iterable and returns 
# the product of all the numbers in it.
def product(iterable):
    p = 1
    for i in iterable:
        p *= i
    return p

# Test the product function a few times:
print("product(range(10)):", product(range(10)))
print("product(range(1, 11)):", product(range(1, 11)))
print("product(range(1, 6, 2)):", product(range(1, 6, 2)))
print("product(range(1, 10, 2)):", product(range(1, 10, 2)))
print()

# Now use the product function with the combinations function 
# to solve Daily Coding Problem #69:
print("max(map(product, combinations(lis, 3)):", \
    max(map(product, combinations(lis, 3))))

# Now let's solve the same problem with reduce and operator.mul 
# instead of the product function above:

# Here is the docstring for reduce:
print("reduce.__doc__:", reduce.__doc__)
print

from operator import mul

# Here is the docstring for mul:
print("operator.mul.__doc__:", mul.__doc__)
print()

# Show how reduce works with mul with a few examples:
print("reduce(mul, range(1, 5)):", reduce(mul, range(1, 5)))
print("reduce(mul, range(3, 7)):", reduce(mul, range(3, 7)))
print()

# Use reduce-with-mul instead of product.
print("max(map(lambda s: reduce(mul, s), combinations(lis, 3))):", \
    max(map(lambda s: reduce(mul, s), combinations(lis, 3))))

# Here's the call using product again for comparison:
print("max(map(product, combinations(lis, 3))):", \
    max(map(product, combinations(lis, 3))))
print()

# A few more calls to the reduce-with-mul version:
lis4 = range(1, 5)
print("lis4:", lis4)
print("max(map(lambda s: reduce(mul, s), combinations(lis4, 3))):", \
    max(map(lambda s: reduce(mul, s), combinations(lis4, 3))))
print()

lis6 = range(1, 7)
print("lis6:", lis6)
print("max(map(lambda s: reduce(mul, s), combinations(lis6, 3))):", \
    max(map(lambda s: reduce(mul, s), combinations(lis6, 3))))
print()

lis7 = range(1, 8)
print("lis7:", lis7)
print("max(map(lambda s: reduce(mul, s), combinations(lis7, 3))):", \
    max(map(lambda s: reduce(mul, s), combinations(lis7, 3))))
print()

# And finally, here is the solution run again with the example 
# input given in the Facebook problem mentioned above:

lis_fb = [-10, -10, 5, 2]
print("lis_fb:", lis_fb)
print("max(map(lambda s: reduce(mul, s), combinations(lis_fb, 3))):", \
    max(map(lambda s: reduce(mul, s), combinations(lis_fb, 3))))
print()

# The result matches the given answer, 500.

# Now let's modify the Faceboook input and run the code again:
lis_fb2 = [-10, 8, -10, 9, 5, 7, 2]
# (Added values 8, 9 and 7 to the list.)
print("lis_fb2:", lis_fb2)
print("max(map(lambda s: reduce(mul, s), combinations(lis_fb2, 3))):", \
    max(map(lambda s: reduce(mul, s), combinations(lis_fb2, 3))))
print()

# The result is right again, since -10 * -10 * 9 = 900 is 
# the largest product.

Here is the output of a run of the program using Python 3:
lis: range(1, 6)
combinations(lis, 3): <itertools.combinations object at 0x0000000001DA9598>
list(combinations(lis, 3)):
(1, 2, 3)
(1, 2, 4)
(1, 2, 5)
(1, 3, 4)
(1, 3, 5)
(1, 4, 5)
(2, 3, 4)
(2, 3, 5)
(2, 4, 5)
(3, 4, 5)

product(range(10)): 0
product(range(1, 11)): 3628800
product(range(1, 6, 2)): 15
product(range(1, 10, 2)): 945

max(map(product, combinations(lis, 3)): 60
reduce.__doc__: reduce(function, sequence[, initial]) -> value

Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
of the sequence in the calculation, and serves as a default when the
sequence is empty.
operator.mul.__doc__: Same as a * b.

reduce(mul, range(1, 5)): 24
reduce(mul, range(3, 7)): 360

max(map(lambda s: reduce(mul, s), combinations(lis, 3))): 60
max(map(product, combinations(lis, 3))): 60

lis4: range(1, 5)
max(map(lambda s: reduce(mul, s), combinations(lis4, 3))): 24

lis6: range(1, 7)
max(map(lambda s: reduce(mul, s), combinations(lis6, 3))): 120

lis7: range(1, 8)
max(map(lambda s: reduce(mul, s), combinations(lis7, 3))): 210

lis_fb: [-10, -10, 5, 2]
max(map(lambda s: reduce(mul, s), combinations(lis_fb, 3))): 500

lis_fb2: [-10, 8, -10, 9, 5, 7, 2]
max(map(lambda s: reduce(mul, s), combinations(lis_fb2, 3))): 900

I also tested it with Python 2 and it gave basically the same output, 
maybe with the exception of some minor message differences between 2 and 3.
So I'm not showing the 2 output here.

The image at the top of the post is of stock with bay leaf and thyme being reduced in a pan.
Here is the Wikipedia article about reduction in cooking.

The functional programming meaning of reduce sort of matches the cooking meaning, right? Heh.

Enjoy.


- Vasudev Ram - Online Python training and consulting

I conduct online courses on Python programming, Unix / Linux commands and shell scripting and SQL programming and database design, with course material and personal coaching sessions.

The course details and testimonials are here.

Contact me for details of course content, terms and schedule.

Try FreshBooks: Create and send professional looking invoices in less than 30 seconds.

Getting a new web site or blog, and want to help preserve the environment at the same time? Check out GreenGeeks.com web hosting.

Sell your digital products via DPD: Digital Publishing for Ebooks and Downloads.

Learning Linux? Hit the ground running with my vi quickstart tutorial. I wrote it at the request of two Windows system administrator friends who were given additional charge of some Unix systems. They later told me that it helped them to quickly start using vi to edit text files on Unix. Of course, vi/vim is one of the most ubiquitous text editors around, and works on most other common operating systems and on some uncommon ones too, so the knowledge of how to use it will carry over to those systems too.

Check out WP Engine, powerful WordPress hosting.

Sell More Digital Products With SendOwl.

Get a fast web site with A2 Hosting.

Creating online products for sale? Check out ConvertKit, email marketing for online creators.

Teachable: feature-packed course creation platform, with unlimited video, courses and students.

Posts about: Python * DLang * xtopdf

My ActiveState Code recipes

Follow me on:


Tuesday, January 22, 2019

Factorial one-liner using reduce and mul for Python 2 and 3


- By Vasudev Ram - Online Python training / SQL training / Linux training

$ foo bar | baz

Hi, readers,

A couple of days ago, I wrote this post for computing factorials using the reduce and operator.mul functions:

Factorial function using Python's reduce function

A bit later I realized that it can be made into a Python one-liner. Here is the one-liner - it works in both Python 2 and Python 3:
$ py -2 -c "from __future__ import print_function; from functools 
import reduce; from operator import mul; print(list(reduce(mul, 
range(1, fact_num + 1)) for fact_num in range(1, 11)))"
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]

$ py -3 -c "from __future__ import print_function; from functools 
import reduce; from operator import mul; print(list(reduce(mul, 
range(1, fact_num + 1)) for fact_num in range(1, 11)))"
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]

(I've split the commands above across multiple lines to avoid truncation while viewing, but if trying them out, enter each of the above commands on a single line.)

A small but interesting point is that one of the imports is not needed in Python 2, and the other is not needed in Python 3:

- importing print_function is not needed in Py 3, because in 3, print is a function, not a statement - but it is not an error to import it, for compatibility with Py 2 code - where it actually needs to be imported for compatibility with Py 3 code (for using print as a function), ha ha.

- importing reduce is not needed in Py 2, because in 2, reduce is both a built-in and also available in the functools module - and hence it is not an error to import it.

Because of the above two points, the same one-liner works in both Py 2 and Py 3.

Can you think of a similar Python one-liner that gives the same output as the above (and for both Py 2 and 3), but can work without one of the imports above (but by removing the same import for both Py 2 and 3)? If so, type it in a comment on the post.

py is The Python launcher for Windows.

Enjoy.


- Vasudev Ram - Online Python training and consulting

I conduct online courses on Python programming, Unix / Linux commands and shell scripting and SQL programming and database design, with course material and personal coaching sessions.

The course details and testimonials are here.

Contact me for details of course content, terms and schedule.

Getting a new web site or blog, and want to help preserve the environment at the same time? Check out GreenGeeks.com web hosting.

Try FreshBooks: Create and send professional looking invoices in less than 30 seconds.

Learning Linux? Hit the ground running with my vi quickstart tutorial. I wrote it at the request of two Windows system administrator friends who were given additional charge of some Unix systems. They later told me that it helped them to quickly start using vi to edit text files on Unix. Of course, vi/vim is one of the most ubiquitous text editors around, and works on most other common operating systems and on some uncommon ones too, so the knowledge of how to use it will carry over to those systems too.

Check out WP Engine, powerful WordPress hosting.

Creating online products for sale? Check out ConvertKit, email marketing for online creators.

Teachable: feature-packed course creation platform, with unlimited video, courses and students.

Posts about: Python * DLang * xtopdf

My ActiveState Code recipes

Follow me on:




Monday, January 21, 2019

Factorial function using Python's reduce function


- By Vasudev Ram - Online Python training / SQL training / Linux training



[This is a beginner-level Python post. I label such posts as "python-beginners" in the Blogger labels at the bottom of the post. You can get a sub-feed of all such posts for any label using the label (case-sensitive) in a URL of the form:

https://jugad2.blogspot.com/search/label/label_name where label_name is to be replaced by an actual label,

such as in:

jugad2.blogspot.com/search/label/python-beginners

and

jugad2.blogspot.com/search/label/python
]

Hi, readers,

The factorial function (Wikipedia article) is often implemented in programming languages as either an iterative or a recursive function. Both are fairly simple to implement.

For the iterative version, to find the value of n factorial (written n! in mathematics), you set a variable called, say, product, equal to 1, then multiply it in a loop by each value of a variable i that ranges from 1 to n.

For the recursive version, you define the base case as 0! = 1, and then for all higher values of n factorial, you compute them recursively as the product of n with (n - 1) factorial.

[ Wikipedia article about Iteration. ]

[ Wikipedia article about Recursion in computer_science. ]

Here is another way of doing it, which is also iterative, but uses no explicit loop; instead it uses Python's built-in reduce() function, which is part of the functional programming paradigm or style:
In [179]: for fact_num in range(1, 11):
     ...:     print reduce(mul, range(1, fact_num + 1))
     ...:
1
2
6
24
120
720
5040
40320
362880
3628800
The above snippet (run in IPython - command-line version), loops over the values 1 to 10, and computes the factorial of each of those values, using reduce with operator.mul (which is a functional version of the multiplication operator). In more detail: the function call range(1, 11) returns a list with the values 1 to 10, and the for statement iterates over those values, passing each to the expression involving reduce and mul, which together compute each value's factorial, using the iterable returned by the second range call, which produces all the numbers that have to be multiplied together to get the factorial of fact_num.

The Python docstring for reduce:
reduce.__doc__: reduce(function, sequence[, initial]) -> value

Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
of the sequence in the calculation, and serves as a default when the
sequence is empty.
Did you know that there are many different kinds of factorials? To learn more, check out this post:

Permutation facts

- Enjoy.


- Vasudev Ram - Online Python training and consulting

I conduct online courses on Python programming, Unix / Linux commands and shell scripting and SQL programming and database design, with course material and personal coaching sessions.

The course details and testimonials are here.

Contact me for details of course content, terms and schedule.

Try FreshBooks: Create and send professional looking invoices in less than 30 seconds.

Getting a new web site or blog, and want to help preserve the environment at the same time? Check out GreenGeeks.com web hosting.

Learning Linux? Hit the ground running with my vi quickstart tutorial. I wrote it at the request of two Windows system administrator friends who were given additional charge of some Unix systems. They later told me that it helped them to quickly start using vi to edit text files on Unix. Of course, vi/vim is one of the most ubiquitous text editors around, and works on most other common operating systems and on some uncommon ones too, so the knowledge of how to use it will carry over to those systems too.

Check out WP Engine, powerful WordPress hosting.

Sell More Digital Products With SendOwl.

Creating online products for sale? Check out ConvertKit, email marketing for online creators.

Teachable: feature-packed course creation platform, with unlimited video, courses and students.

Posts about: Python * DLang * xtopdf

My ActiveState Code recipes

Follow me on:


Thursday, January 3, 2019

Multiple item search in an unsorted list in Python


- By Vasudev Ram - Online Python training / SQL training / Linux training



Hi, readers,

I was reviewing simple algorithms with a view to using some as examples or exercises in my Python programming course. While doing so, I thought of enhancing simple linear search for one item in a list, to make it search for multiple items.

Here are a couple of program versions I wrote for that task. They use straightforward logic. There are just a few additional points:

- In both programs, I use a generator to yield the values found (the index and the item).
- In the first program, I print out the index and item for each item found.
- In the second program, I mark where the items are found with text "arrows".

This is the first program, mult_item_search_unsorted_list.py:
# mult_item_search_unsorted_list.py 
# Purpose: To search for multiple items in an unsorted list.
# Prints each item found and its index.
# Author: Vasudev Ram
# Copyright 2019 Vasudev Ram
# Training: https://jugad2.blogspot.com/p/training.html
# Blog: https://jugad2.blogspot.com
# Web site: https://vasudevram.github.io
# Product store: https://gumroad.com/vasudevram

from __future__ import print_function
import sys
from random import sample, shuffle

def mult_item_search_unsorted_list(dlist, slist):
    for didx, ditem in enumerate(dlist):
        for sitem in slist:
            if sitem == ditem:
                yield (didx, ditem)

def main():
    # Create the search list (slist) with some items that will be found 
    # and some that will not be found in the data list (dlist) below.
    slist = sample(range(0, 10), 3) + sample(range(10, 20), 3)
    # Create the data list.
    dlist = range(10)
    for i in range(3):
        # Mix it up, DJ.
        shuffle(slist)
        # MIX it up, DEK.
        shuffle(dlist)
        print("\nSearching for:", slist)
        print("    in:", dlist)
        for didx, ditem in mult_item_search_unsorted_list(dlist, slist):
            print("        found {} at index {}".format(ditem, didx))
    
main()
Output of a run:
$ python mult_item_search_unsorted_list.py

Searching for: [1, 18, 3, 15, 19, 4]
    in: [8, 9, 1, 2, 0, 7, 5, 3, 6, 4]
        found 1 at index 2
        found 3 at index 7
        found 4 at index 9

Searching for: [4, 19, 18, 15, 1, 3]
    in: [7, 5, 8, 2, 9, 4, 0, 3, 6, 1]
        found 4 at index 5
        found 3 at index 7
        found 1 at index 9

Searching for: [1, 3, 4, 18, 19, 15]
    in: [9, 6, 1, 8, 7, 4, 3, 0, 2, 5]
        found 1 at index 2
        found 4 at index 5
        found 3 at index 6
And this is the second program, mult_item_search_unsorted_list_w_arrows.py:
# mult_item_search_unsorted_list_w_arrows.py 
# Purpose: To search for multiple items in an unsorted list.
# Marks the position of the items found with arrows.
# Author: Vasudev Ram
# Copyright 2019 Vasudev Ram
# Training: https://jugad2.blogspot.com/p/training.html
# Blog: https://jugad2.blogspot.com
# Web site: https://vasudevram.github.io
# Product store: https://gumroad.com/vasudevram

from __future__ import print_function
import sys
from random import sample, shuffle

def mult_item_search_unsorted_list(dlist, slist):
    for didx, ditem in enumerate(dlist):
        for sitem in slist:
            if sitem == ditem:
                yield (didx, ditem)

def main():
    # Create the search list (slist) with some items that will be found 
    # and some that will not be found in the data list (dlist) below.
    slist = sample(range(10), 4) + sample(range(10, 20), 4)
    # Create the data list.
    dlist = range(10)
    for i in range(3):
        # Mix it up, DJ.
        shuffle(slist)
        # MIX it up, DEK.
        shuffle(dlist)
        print("\nSearching for: {}".format(slist))
        print("    in: {}".format(dlist))
        for didx, ditem in mult_item_search_unsorted_list(dlist, slist):
            print("---------{}^".format('---' * didx))
    
main()
Output of a run:
$ python mult_item_search_unsorted_list_w_arrows.py

Searching for: [16, 0, 15, 4, 6, 1, 10, 12]
    in: [8, 9, 0, 1, 5, 4, 7, 2, 6, 3]
---------------^
------------------^
------------------------^
---------------------------------^

Searching for: [6, 16, 10, 0, 1, 4, 12, 15]
    in: [2, 7, 0, 8, 1, 4, 6, 3, 9, 5]
---------------^
---------------------^
------------------------^
---------------------------^

Searching for: [0, 12, 4, 10, 6, 16, 1, 15]
    in: [8, 1, 0, 7, 9, 6, 2, 5, 4, 3]
------------^
---------------^
------------------------^
---------------------------------^

In a recent post, Dynamic function creation at run time with Python's eval built-in, I had said:

"Did you notice any pattern to the values of g(i)? The values are 1, 4, 9, 16, 25 - which are the squares of the integers 1 to 5. But the formula I entered for g was not x * x, rather, it was x * x + 2 * x + 1. Then why are squares shown in the output? Reply in the comments if you get it, otherwise I will answer next time."

No reader commented with a solution. So here is a hint to figure it out:

What is the expansion of (a + b) ** 2 (a plus b the whole squared) in algebra?

Heh.

The drawing of the magnifying glass at the top of the post is by:

Yours truly.

( The same one that I used in this post:
Command line D utility - find files matching a pattern under a directory )

I'll leave you with another question: What, if any, could be the advantage of using Python generators in programs like these?
Notice that I said "programs like these", not "these programs".

Enjoy.

- Vasudev Ram - Online Python training and consulting

I conduct online courses on Python programming, Unix / Linux commands and shell scripting and SQL programming and database design, with course material and personal coaching sessions.

The course details and testimonials are here.

Contact me for details of course content, terms and schedule.

Try FreshBooks: Create and send professional looking invoices in less than 30 seconds.

Getting a new web site or blog, and want to help preserve the environment at the same time? Check out GreenGeeks.com web hosting.

Sell your digital products via DPD: Digital Publishing for Ebooks and Downloads.

Learning Linux? Hit the ground running with my vi quickstart tutorial. I wrote it at the request of two Windows system administrator friends who were given additional charge of some Unix systems. They later told me that it helped them to quickly start using vi to edit text files on Unix. Of course, vi/vim is one of the most ubiquitous text editors around, and works on most other common operating systems and on some uncommon ones too, so the knowledge of how to use it will carry over to those systems too.

Check out WP Engine, powerful WordPress hosting.

Get a fast web site with A2 Hosting.

Creating online products for sale? Check out ConvertKit, email marketing for online creators.

Teachable: feature-packed course creation platform, with unlimited video, courses and students.

Posts about: Python * DLang * xtopdf

My ActiveState Code recipes

Follow me on:


Monday, December 3, 2018

Tower of Hanoi program in Higher-Order Perl book, ported to Python


Hi, readers,

I was reading the book Higher Order Perl (Wikipedia entry). It is by Mark Jason Dominus, a well-known figure in the Perl community. I've only read a bit of it so far, but it already looks very good. There are also many reviews of it, all of which say that it is a good book, including one by Damian Conway, another well-known Perl figure.

Early in the book, in chapter 1 - Recursion and Callbacks, there is a nice example program showing how to solve the Tower of Hanoi problem. I had come across the problem earlier, but had not seen a Perl solution before. It's not really any different from the same kind of solution written in other languages, except for some points related to Perl's syntax and semantics, such as the use of local (Perl's my) vs. global variables, specifically with regard to a recursive function, which is what Mark uses for Hanoi.

Anyway, since I had not implemented Hanoi before, I thought of porting Mark's hanoi function from Perl to Python. It's an easy recursive algorithm. (The Wikipedia article has multiple algorithms for Hanoi, some non-recursive too.)

I wrote two versions: the first is hard-coded to solve it for a tower with n equal to 3, where n is the number of disks, and the second does it in a loop for n ranging from 1 to 4, with a prompt and a pause after each one.

If you press q at any of the prompts, the program quits. If you press any other key, it goes on to the next iteration, until the last one. For reading a keypress without needing to press Enter, I used the getch function (get character) from the msvcrt module that comes with Python. MSVCRT stands for Microsoft Visual C Run Time.

So this program is Windows-specific. There are equivalent ways of reading a character without needing to press Enter, for Linux too, but they usually involve some low-level fiddling with the tty / terminal settings, termios, etc. I think ActiveState Code has a recipe for a getch-like function that works on Linux.

Here is the first version, hanoi_01.py:

from __future__ import print_function

"""
This is the code for the Perl version by Mark Jason Dominus:

sub hanoi {
    my ($n, $start, $end, $extra) = @_;
    if ($n == 1) {
        print "Move disk #1 from $start to $end.\n"; # Step 1
    } else {
    hanoi($n-1, $start, $extra, $end); # Step 2
    print "Move disk #$n from $start to $end.\n"; # Step 3
    hanoi($n-1, $extra, $end, $start); # Step 4
    }
}
"""

# This is my Python version ported from the Perl version above:

def hanoi(n, start, end, extra):
    """
    Function hanoi(n, start, end, extra)
    Solve Tower of Hanoi problem for a tower of n disks,
    of which the largest is disk #n. Move the entire tower from
    peg 'start' to peg 'end', using peg 'extra' as a work space.
    """
    if n == 1:
        print("Move disk #1 from {} to {}.\n".format(start, end))
    else:
        # Recursive call #1
        hanoi(n - 1, start, extra, end)
        print("Move disk #{} from {} to {}.\n".format(n, start, end))
        # Recursive call #2
        hanoi(n - 1, extra, end, start)
        
# Call to hanoi() with 3 disks, i.e. n = 3:
hanoi(3, 'A', 'C', 'B')
Here is the output on running it:
$ python hanoi_01.py
Move disk #1 from A to C.

Move disk #2 from A to B.

Move disk #1 from C to B.

Move disk #3 from A to C.

Move disk #1 from B to A.

Move disk #2 from B to C.

Move disk #1 from A to C.
Here is the second version, hanoi_02.py:
from __future__ import print_function
from msvcrt import getch

"""
Tower of Hanoi program
---
By Vasudev Ram
Web site: https://vasudevram.github.io
Blog: https://jugad2.blogspot.com
Twitter: https://mobile.twitter.com/vasudevram
Product store: https://gumroad.com/vasudevram
---
Translated to Python from the Perl version in the book Higher-Order Perl
by Mark Jason Dominus: https://hop.perl.plover.com/book/ , with some 
minor enhancements related to interactivity.
"""

def hanoi(n, start, end, extra):
    """
    Function hanoi(N, start, end, extra)
    Solve Tower of Hanoi problem for a tower of N disks,
    of which the largest is disk #N. Move the entire tower from
    peg 'start' to peg 'end', using peg 'extra' as a work space.
    """
    assert n > 0
    if n == 1:
        print("Move disk #1 from {} to {}.".format(start, end))
    else:
        hanoi(n - 1, start, extra, end)
        print("Move disk #{} from {} to {}.".format(n, start, end))
        hanoi(n - 1, extra, end, start)
        
for n in range(1, 5):
    print("\nTower of Hanoi with n = {}:".format(n))
    hanoi(n, 'A', 'C', 'B')
    if n < 4:
        print("\nPress q to quit, any other key for next run: ")
        c = getch()
        if c.lower() == 'q':
            break

Here is the output on running it - I pressed q after 3 iterations:
$ python hanoi_02.py

Tower of Hanoi with n = 1:
Move disk #1 from A to C.

Press q to quit, any other key for next run:

Tower of Hanoi with n = 2:
Move disk #1 from A to B.
Move disk #2 from A to C.
Move disk #1 from B to C.

Press q to quit, any other key for next run:

Tower of Hanoi with n = 3:
Move disk #1 from A to C.
Move disk #2 from A to B.
Move disk #1 from C to B.
Move disk #3 from A to C.
Move disk #1 from B to A.
Move disk #2 from B to C.
Move disk #1 from A to C.

Press q to quit, any other key for next run:
Note that getch does not echo the key that is pressed to the screen. If you want that, use getche, from the same module msvcrt.

Viewing the output, I observed that for 1 disk, it takes 1 move, for 2 disks, it takes 3 moves, and for 3 disks, it takes 7 moves. From this, by informally applying mathematical induction, we can easily figure out that for n disks, it will take 2 ** n - 1 moves. The Wikipedia article about the Tower of Hanoi confirms this.

That same Wikipedia article (linked above) also shows that the Tower of Hanoi has some interesting applications:

Excerpts:

[ The Tower of Hanoi is frequently used in psychological research on problem solving. There also exists a variant of this task called Tower of London for neuropsychological diagnosis and treatment of executive functions. ]

[ Zhang and Norman[10] used several isomorphic (equivalent) representations of the game to study the impact of representational effect in task design. ]

[ The Tower of Hanoi is also used as a Backup rotation scheme when performing computer data Backups where multiple tapes/media are involved. ]

[ The Tower of Hanoi is popular for teaching recursive algorithms to beginning programming students. ]

And this application is possibly the most interesting of the lot - ants solving the Tower of Hanoi problem :)

[ In 2010, researchers published the results of an experiment that found that the ant species Linepithema humile were successfully able to solve the 3-disk version of the Tower of Hanoi problem through non-linear dynamics and pheromone signals. ]

Also check out the section in that Wikipedia article with the title:

"General shortest paths and the number 466/885"

Not directly related, but similar to the above ratio, did you know that there is an easy-to-remember and better approximation to the number pi, than the ratio 22/7 that many of us learned in school?

Just take the 1st 3 odd numbers, i.e. 1, 3, 5, repeat each of them once, and join all those 6 digits, to get 113355, split that number in the middle, and divide the 2nd half by the 1st half, i.e 355/113, which gives 3.1415929203539823008849557522124. (See the section titled "Approximate value and digits" in the Wikipedia article about pi linked above, for this and other approximations for pi).

Pressing the pi button in Windows CALC.EXE gives 3.1415926535897932384626433832795, and comparing that with the ratio 355/113 above, shows that the ratio is accurate to 6 decimal places. I've read somewhere that this ratio was used by mathematicians in ancient India.

Here are some interesting excerpts from the Wikipedia article about pi:

[ The number pi is a mathematical constant. Originally defined as the ratio of a circle's circumference to its diameter, it now has various equivalent definitions and appears in many formulas in all areas of mathematics and physics. It is approximately equal to 3.14159. It has been represented by the Greek letter "p" since the mid-18th century, though it is also sometimes spelled out as "pi". It is also called Archimedes' constant. ]

[ Being an irrational number, pi cannot be expressed as a common fraction (equivalently, its decimal representation never ends and never settles into a permanently repeating pattern). Still, fractions such as 22/7 and other rational numbers are commonly used to approximate pi. The digits appear to be randomly distributed. In particular, the digit sequence of pi is conjectured to satisfy a specific kind of statistical randomness, but to date, no proof of this has been discovered. Also, pi is a transcendental number; that is, it is not the root of any polynomial having rational coefficients. ]

[ Being an irrational number, pi cannot be expressed as a common fraction (equivalently, its decimal representation never ends and never settles into a permanently repeating pattern). Still, fractions such as 22/7 and other rational numbers are commonly used to approximate p. The digits appear to be randomly distributed. In particular, the digit sequence of pi is conjectured to satisfy a specific kind of statistical randomness, but to date, no proof of this has been discovered. Also, pi is a transcendental number; that is, it is not the root of any polynomial having rational coefficients. This transcendence of pi implies that it is impossible to solve the ancient challenge of squaring the circle with a compass and straightedge. ]

[ Ancient civilizations required fairly accurate computed values to approximate pi for practical reasons, including the Egyptians and Babylonians. Around 250 BC the Greek mathematician Archimedes created an algorithm for calculating it. In the 5th century AD Chinese mathematics approximated pi to seven digits, while Indian mathematics made a five-digit approximation, both using geometrical techniques. The historically first exact formula for p, based on infinite series, was not available until a millennium later, when in the 14th century the Madhava–Leibniz series was discovered in Indian mathematics. ]

(Speaking of Indian mathematics, check out this earlier post by me:

Bhaskaracharya and the man who found zero.)

[ Because its most elementary definition relates to the circle, pi is found in many formulae in trigonometry and geometry, especially those concerning circles, ellipses, and spheres. In more modern mathematical analysis, the number is instead defined using the spectral properties of the real number system, as an eigenvalue or a period, without any reference to geometry.

It appears therefore in areas of mathematics and the sciences having little to do with the geometry of circles, such as number theory and statistics, as well as in almost all areas of physics.

The ubiquity of pi makes it one of the most widely known mathematical constants both inside and outside the scientific community. Several books devoted to pi have been published, and record-setting calculations of the digits of pi often result in news headlines. Attempts to memorize the value of pi with increasing precision have led to records of over 70,000 digits. ]

- Enjoy.


- Vasudev Ram - Online Python training and consulting


I conduct online courses on Python programming, Unix / Linux commands and shell scripting and SQL programming and database design, with course material and personal coaching sessions.

The course details and testimonials are here.

Contact me for details of course content, terms and schedule.

Try FreshBooks: Create and send professional looking invoices in less than 30 seconds.

Getting a new web site or blog, and want to help preserve the environment at the same time? Check out GreenGeeks.com web hosting.

Sell your digital products via DPD: Digital Publishing for Ebooks and Downloads.

Learning Linux? Hit the ground running with my vi quickstart tutorial.

I wrote it at the request of two Windows system administrator friends who were given additional charge of some Unix systems. They later told me that it helped them to quickly start using vi to edit text files on Unix. Of course, vi/vim is one of the most ubiquitous text editors around, and works on most other common operating systems and on some uncommon ones too, so the knowledge of how to use it will carry over to those systems too.

Check out WP Engine, powerful WordPress hosting.

Sell More Digital Products With SendOwl.

Get a fast web site with A2 Hosting.

Creating online products for sale? Check out ConvertKit, email marketing for online creators.

Teachable: feature-packed course creation platform, with unlimited video, courses and students.

Posts about: Python * DLang * xtopdf

My ActiveState Code recipes

Follow me on:


Sunday, October 28, 2018

BASE CS: Exploring the basics of computer science, every Monday, for a year.

By Vasudev Ram

Saw this recently.

basecs: Exploring the basics of computer science, every Monday, for a year.

It's by Vaidehi Joshi, a software engineer who works at Tilde, a company that includes Yehuda Katz, who worked or works on Ember.js, Rails, JQuery and Rust.

Browsed a few of the posts there. Seems good.


- Vasudev Ram - Online Python training and consulting

I conduct online courses on Python programming, Unix/Linux (commands and shell scripting) and SQL programming and database design, with personal coaching sessions.

Here are the course details and some testimonials.

DPD: Digital Publishing for Ebooks and Downloads.

Learning Linux or any other Unix-like OS, like macOS or *BSD?
Hit the ground running with my vi quickstart tutorial. I wrote it for two Windows system administrator friends who were given charge of Unix systems. They said it made it easy for them to start using vi on Unix. Since vim is a superset of vi, it works for vim too.

Check out WP Engine, powerful WordPress hosting.

Creating or want to create online products for sale? Check out ConvertKit, email marketing for online creators.

Teachable: feature-packed course creation platform, with unlimited video, courses and students.

Posts about: Python * DLang * xtopdf

My ActiveState Code recipes

Follow me on:


Sunday, September 23, 2018

How many ways can you substring a string? Part 2


By Vasudev Ram


Twine image attribution

Hi readers,

In my last post, i.e.:

How many ways can you substring a string? Part 1, I had said that there can be other ways of doing it, and that some enhancements were possible. This post (Part 2) is about that.

Here is another algorithm to find all substrings of a given string:

Let s be the input string.
Let n be the length of s.
Find and yield all substrings of s of length 1.
Find and yield all substrings of s of length 2.
...
Find and yield all substrings of s of length n.

Even without doing any formal analysis of the algorithm, we can intuitively see that it is correct, because it accounts for all possible cases (except for the empty string, but adding that is trivial).

[ BTW, what about uses for this sort of program? Although I just wrote it for fun, one possible use could be in word games like Scrabble. ]

The code for this new algorithm is in program all_substrings2.py below.
"""
all_substrings2.py
Function and program to find all substrings of a given string.
Author: Vasudev Ram
Copyright 2018 Vasudev Ram
Web site: https://vasudevram.github.io
Blog: https://jugad2.blogspot.com
Twitter: https://mobile.twitter.com/vasudevram
Product store: https://gumroad.com/vasudevram
"""

from __future__ import print_function
import sys
from error_exit import error_exit
from debug1 import debug1

def usage():
    message_lines = [\
        "Usage: python {} a_string".format(sa[0]),
        "Print all substrings of a_string.",
        "",
    ]
    sys.stderr.write("\n".join(message_lines))

def all_substrings2(s):
    """
    Generator function that yields all the substrings 
    of a given string s.
    Algorithm used:
    1. len_s = len(s)
    2. if len_s == 0, return ""
    3. (else len_s is > 0):
       for substr_len in 1 to len_s:
           find all substrings of s that are of length substr_len
           yield each such substring 
    Expected output for some strings:
    For "a":
        "a"
    For "ab":
        "a"
        "b"
        "ab"
    For "abc:
        "a"
        "b"
        "c"
        "ab"
        "bc"
        "abc"
    For "abcd:
        "a"
        "b"
        "c"
        "d"
        "ab"
        "bc"
        "cd"
        "abc"
        "bcd"
        "abcd"
    """

    len_s = len(s)
    substr_len = 1
    while substr_len <= len_s:
        start = 0
        end = start + substr_len
        while end <= len_s:
            debug1("s[{}:{}] = {}".format(\
                start, end, s[start:end]))
            yield s[start:end]
            start += 1
            end = start + substr_len
        substr_len += 1

def main():
    if lsa != 2:
        usage()
        error_exit("\nError: Exactly one argument must be given.\n")

    if sa[1] == "":
        print("")
        sys.exit(0)

    for substring in all_substrings2(sa[1]):
        print(substring)

sa = sys.argv
lsa = len(sa)

if __name__ == "__main__":
    main()
BTW, I added the empty string as the last item in the message_lines list (in the usage() function), as a small trick, to avoid having to explicitly add an extra newline after the joined string in the write() call.

Here are some runs of the program, with outputs, using Python 2.7 on Linux:

(pyo, in the commands below, is a shell alias I created for 'python -O', to disable debugging output. And a*2*y expands to all_substrings2.py, since there are no other filenames matching that wildcard pattern in my current directory. It's a common Unix shortcut to save typing. In fact, the bash shell expands that shortcut to the full filename when you type the pattern and then press Tab. But the expansion happens without pressing Tab too, if you just type that command and hit Enter. But you have to know for sure, up front, that the wildcard expands to only one filename (if you want that), or you can get wrong results, e.g. if such a wildcard expands to 3 filenames, and your program expects command-line arguments, the 2nd and 3rd filenames will be treated as command-line arguments for the program represented by the 1st filename. This will likely not be what you want, and may create problems.)

Run it without any arguments:
$ pyo a*2*y
Usage: python all_substrings2.py a_string
Print all substrings of a_string.

Error: Exactly one argument must be given.
Run a few times with some input strings of incrementally longer lengths:
$ pyo a*2*y a
a
$ pyo a*2*y ab
a
b
ab
$ pyo a*2*y abc
a
b
c
ab
bc
abc
$ pyo a*2*y abcd
a
b
c
d
ab
bc
cd
abc
bcd
abcd
Count the number of substrings in the above run for string abcd:
$ pyo a*2*y abcd | wc -l
10
$ pyo a*2*y abcde
a
b
c
d
e
ab
bc
cd
de
abc
bcd
cde
abcd
bcde
abcde
Count the number of substrings in the above run for string abcde:
$ pyo a*2*y abcde | wc -l
15
$ pyo a*2*y abcdef
a
b
c
d
e
f
ab
bc
cd
de
ef
abc
bcd
cde
def
abcd
bcde
cdef
abcde
bcdef
abcdef
Count the number of substrings in the above run for string abcdef:
$ pyo a*2*y abcdef | wc
     21      21      77
Now a few more with only the count:
$ pyo a*2*y abcdefg | wc
     28      28     112
$ pyo a*2*y abcdefgh | wc
     36      36     156
$ pyo a*2*y abcdefghi | wc
     45      45     210
Notice a pattern?

The count of substrings for each succeeding run (which has one more character in the input string than the preceding run has), is equal to the sum of the count for the preceding run and the length of the input string for the succeeding run; e.g. 10 + 5 = 15, 15 + 6 = 21, 21 + 7 = 28, etc. This is the same as the sum of the first n natural numbers.

There is a well-known formula for that sum: n * (n + 1) / 2.

There is a story (maybe apocryphal) that the famous mathematician Gauss was posed this problem - to find the sum of the numbers from 1 to 100 - by his teacher, after he misbehaved in class. To the surprise of the teacher, he gave the answer in seconds. From the Wikipedia article about Gauss:

[ Gauss's presumed method was to realize that pairwise addition of terms from opposite ends of the list yielded identical intermediate sums: 1 + 100 = 101, 2 + 99 = 101, 3 + 98 = 101, and so on, for a total sum of 50 × 101 = 5050. ]

From this we can see that the sum of this sequence satisfies the formula n * (n + 1) / 2, where n = 100, i.e. 100 * (100 + 1) / 2 = 50 * 101.

(Wikipedia says that Gauss "is ranked among history's most influential mathematicians".)

We can also run the all_substrings2.py program multiple times with different inputs, using a for loop in the shell:
$ for s in a ab abc abcd
> do
>   echo All substrings of $s:
>   pyo al*2*py $s
> done

All substrings of a:
a
All substrings of ab:
a
b
ab
All substrings of abc:
a
b
c
ab
bc
abc
All substrings of abcd:
a
b
c
d
ab
bc
cd
abc
bcd
abcd
Some remarks on the program versions shown (i.e. all_substrings.py and all_substrings2.py, in Parts 1 and 2 respectively):

Both versions use a generator function, to lazily yield each substring on demand. Either version can easily be changed to use a list instead of a generator (and the basic algorithm used will not need to change, in either case.) To do that, we have to delete the yield statement, collect all the generated substrings in a new list, and at the end, return that list to the caller. The caller's code will not need to change, although we will now be iterating over the list returned from the function, not over the values yielded by the generator. Some of the pros and cons of the two approaches (generator vs. list) are:

- the list approach has to create and store all the substrings first, before it can return them. So it uses memory proportional to the sum of the sizes of all the substrings generated, with some overhead due to Python's dynamic nature (but that per-string overhead exists for the generator approach too). (See this post: Exploring sizes of data types in Python.) The list approach will need a bit of overhead for the list too. But the generator approach needs to handle only one substring at a time, before yielding it to the caller, and does not use a list. So it will potentially use much less memory, particularly for larger input strings. The generator approach may even be faster than the list version, since repeated memory (re)allocation for the list (as it expands) has some overhead. But that is speculation on my part as of now. To be sure of it, one would have to do some analysis and/or some speed measurements of relevant test programs.

- the list approach gives you the complete list of substrings (after the function that generates them returns). So, in the caller, if you want to do multiple processing passes over them, you can. But the generator approach gives you each substring immediately as it is generated, you have to process it, and then it is gone. So you can only do one processing pass over the substrings generated. In other words, the generator's output is sequential-access, forward-only, one-item-at-a-time-only, and single-pass-only. (Unless you store all the yielded substrings, but then that becomes the same as the list approach.)

Another enhancement that can be useful is to output only the unique substrings. As I showed in Part 1, if there are any repeated characters in the input string, there can be duplicate substrings in the output. There are two obvious ways of getting only unique substrings:

1) By doing it internal to the program, using a Python dict. All we have to do is add each substring (as a key, with the corresponding value being anything, say None), to a dict, as and when the substring is generated. Then the substrings in the dict are guaranteed to be unique. Then at the end, we just print the substrings from the dict instead of from the list. If we want to print the substrings in the same order they were generated, we can use an OrderedDict.

See: Python 2 OrderedDict
and: Python 3 OrderedDict

(Note: In Python 3.7, OrderedDict may no longer be needed, because dicts are defined as keeping insertion order.)

2) By piping the output of the program (which is all the generated substrings, one per line) to the Unix uniq command, whose purpose is to select only unique items from its input. But for that, we have to sort the list first, since uniq requires sorted input to work properly. We can do that with pipelines like the following:

First, without sort and uniq; there are duplicates:

$ pyo all_substrings2.py aabbb | nl -ba
1 a
2 a
3 b
4 b
5 b
6 aa
7 ab
8 bb
9 bb
10 aab
11 abb
12 bbb
13 aabb
14 abbb
15 aabbb

Then with sort and uniq; now there are no duplicates:

$ pyo all_substrings2.py aabbb | sort | uniq | nl -ba
1 a
2 aa
3 aab
4 aabb
5 aabbb
6 ab
7 abb
8 abbb
9 b
10 bb
11 bbb

The man pages for sort and uniq are here:

sort
uniq

That's it for now. I have a few more points which I may want to add; if I decide to do so, I'll do them in a Part 3 post.

The image at the top of the post is of spools of twine (a kind of string) from Wikipedia.

- Enjoy.


- Vasudev Ram - Online Python training and consulting

I conduct online courses on Python programming, Unix/Linux (commands and shell scripting) and SQL programming and database design, with personal coaching sessions.

Contact me for details of course content, terms and schedule.

DPD: Digital Publishing for Ebooks and Downloads.

Hit the ground running with my vi quickstart tutorial. I wrote it at the request of two Windows system administrator friends who were given additional charge of some Unix systems. They later told me that it helped them to quickly start using vi to edit text files on Unix.

Check out WP Engine, powerful WordPress hosting.

Creating online products for sale? Check out ConvertKit, email marketing for online creators.

Teachable: feature-packed course creation platform, with unlimited video, courses and students.

Track Conversions and Monitor Click Fraud with Improvely.

Posts about: Python * DLang * xtopdf

My ActiveState Code recipes

Follow me on:


Wednesday, September 12, 2018

How many ways can you substring a string? Part 1


By Vasudev Ram




String image attribution

Recently, something I read made me think of writing a simple program to generate all substrings of a given string.
(To be precise, excluding the null string.)

Here is an initial version I came up with, all_substrings.py:
"""
all_substrings.py
Function and program to find all the substrings of a given string.
Author: Vasudev Ram
Copyright 2018 Vasudev Ram
Web site: https://vasudevram.github.io
Blog: https://jugad2.blogspot.com
Twitter: https://mobile.twitter.com/vasudevram
Product Store: https://gumroad.com/vasudevram
"""

from __future__ import print_function
import sys
from error_exit import error_exit
from debug1 import debug1

def usage():
    message_lines = [\
        "Usage: python {} a_string".format(sa[0]),
        "Print all substrings of a_string.",
    ]
    sys.stderr.write("\n".join(message_lines))

def all_substrings(s):
    """
    Generator function that yields all the substrings of a given string.
    """

    ls = len(s)
    if ls == 0:
        usage()
        error_exit("\nError: String argument must be non-empty.")

    start = 0
    while start < ls:
        end = start + 1
        while end <= ls:
            debug1("s[{}:{}] = {}".format(start, end, s[start:end]))
            yield s[start:end]
            end += 1
        start += 1

def main():
    if lsa != 2:
        usage()
        error_exit("\nError: Exactly one argument must be given.")

    for substring in all_substrings(sa[1]):
        print(substring)

sa = sys.argv
lsa = len(sa)

if __name__ == "__main__":
    main()
Some runs and output of the program:

With no command-line arguments:
$ python all_substrings.py
Usage: python all_substrings.py a_string
Print all substrings of a_string.
Error: Exactly one argument must be given.
With one command-line argument, an empty string:
$ python all_substrings.py ""
Usage: python all_substrings.py a_string
Print all substrings of a_string.
Error: String argument must be non-empty.
Now with a 3-character string, with debugging enabled, via the use of my debug1 debugging function [1] (and Python's __debug__ built-in variable, which is set to True by default):
$ python all_substrings.py abc
s[0:1] = a
a
s[0:2] = ab
ab
s[0:3] = abc
abc
s[1:2] = b
b
s[1:3] = bc
bc
s[2:3] = c
c
[1] You can read about and get the code for that debugging function here:

Improved simple Python debugging function

The remaining runs are with debugging turned off via Python's -O flag:

With a 4-character string:
$ python -O all_substrings.py abcd
a
ab
abc
abcd
b
bc
bcd
c
cd
d
With a 4-character string, not all characters unique:
$ python -O all_substrings.py FEED
F
FE
FEE
FEED
E
EE
EED
E
ED
D
Note that when there are duplicated characters in the input, we can get duplicate substrings in the output; in this case, E appears twice.

With a string of length 6, again with some characters repeated (E and D):
$ python -O all_substrings.py FEEDED
F
FE
FEE
FEED
FEEDE
FEEDED
E
EE
EED
EEDE
EEDED
E
ED
EDE
EDED
D
DE
DED
E
ED
D
Again, we get duplicate substrings in the output.

With a 6-character string, no duplicate characters:
$ python -O all_substrings.py 123456
1
12
123
1234
12345
123456
2
23
234
2345
23456
3
34
345
3456
4
45
456
5
56
6
Is there any other way of doing it?
Any interesting enhancements possible?

Yes to both questions.
I will cover some of those points in a follow-up post.

Actually, I already did one thing in the current version, which is of interest: I used a generator to yield the substrings lazily, instead of creating them all upfront, and then returning them all in a list. I'll show and discuss a few pros and cons of some other approaches later.

Meanwhile, want to have a bit of fun with visual effects?

Try some variations of runs of the program like these:


python -O all_substrings.py +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

python -O all_substrings.py /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

python -O all_substrings.py "%% $$ @@ && %% $$ @@ && %% $$ @@ && %% $$ @@ && %% $$ @@ && %% $$ @@ && %% $$ @@ && %% $$ @@ && %% $$ @@ && %% $$ @@ && %% $"

$ python -O all_substrings.py 10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010

python -O all_substrings.py ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"

You can change the characters used in the string argument to any combination of any punctuation characters, or even letters or digits - anything you like. You can also vary the number of characters used in the string. Longer ones (though not too long) tend to give better visual effects and the display also lasts for longer. Note that all the characters of the string you use, should come on the same single line, the same line as the python command you use. Also, if using a pipe character (|) (or any other characters that are special to your OS shell), enclose the whole string in quotes as I have done in an example above. I ran this on Windows and so used double quotes for such cases. Single quotes give errors. On Unix-like systems, either may work, but some characters may get interpreted inside double quotes. Experiment :)

You can also add an import time statement in the imports section of the program, and then use a time.sleep(number) inside the for loop, say, just above the print(substring) statement. I used values like:
time.sleep(0.002)
which works well for my display. You can tweak that number for your hardware.

- Have fun.

Did you know that there are a large number of meanings and contexts for the word string? Here are some of them:

String (Wikipedia).

This Wikipedia article about strings in computer science is interesting, and has a lot more points than one might imagine at first:

(computer) strings


- Vasudev Ram - Online Python training and consulting

Hit the ground running with my vi quickstart tutorial, vetted by two Windows system administrator friends.

Jump to posts: Python * DLang * xtopdf

Interested in a Python, SQL or Linux course?

Get WP Engine, powerful managed WordPress hosting.

Subscribe to my blog (jugad2.blogspot.com) by email

My ActiveState Code recipes


Follow me on:

Gumroad * LinkedIn * Twitter

Do you create online products? Get Convertkit:

Email marketing for digital product creators


Thursday, June 14, 2018

VIDEO: Good article and video about asymptotic complexity of algorithms

By Vasudev Ram

I saw this nice tutorial about the asympotic complexity of algorithms (Big-Oh notation etc.) via this HN thread:

A Gentle Introduction to Algorithm Complexity Analysis (discrete.gr)

It is by Dionysis Zindros of the University of Athens, Greece.

The HN thread has only a few comments as of now, but one of them led to another good resource on this topic:

Asymptotic Notation, by Jackson Steinkamp of Harvard's CS50 program

The video is also embedded below. It is short, but gives a good idea of the topic.

In my next post, I'll do that analysis of the prime number checker that I ported from Q to Python.

Here is the embedded video:



- Enjoy.

- My Codementor profile

Get fast web hosting with A2Hosting.com

Get updates (via Gumroad) on my forthcoming apps and content.

Jump to posts: Python * DLang * xtopdf

Subscribe to my blog by email

My ActiveState Code recipes

Follow me on: LinkedIn * Twitter

Are you a blogger with some traffic? Get Convertkit:

Email marketing for professional bloggers



Saturday, October 22, 2016

perm_facts version with list comps and functional programming

By Vasudev Ram



Cartoon attribution

A little after writing the program (perm_facts.py) in my recent post:

Permutation facts

(which showed that the number of permutations of n things was the same as n factorial), I saw that I could replace the program's for loops with list comprehensions. So I did that, in the functions num_perms_upto and factorials_upto.

Then I also changed the recursive factorial function to the iterative version shown in the code below. (Although people sometimes use recursive algorithms instead of iterative ones, because they can be simpler to implement, often by using elegant divide and conquer methods), in this case, the recursive version is not really simpler than the iterative one.)

However, I then realized that I could replace the iterative version by a one-line functional version using reduce and operator.mul. So here is the program, perm_fact2.py, with all the changes mentioned above (the iterative version is left in, as comments, but the for loops from the original perm_fact.py are gone, replaced by shorter list comprehensions).

A small benefit of the changes is that the number of lines comes down by a few (if you don't count the commented lines for the iterative version, which I left in there, since it was not in the original), but that was not the goal of the exercise - I was just exploring different ways of doing it.

And whether the code is clearer or not after the changes, may be a matter of personal opinion. For those used to the procedural / imperative style, the changes may make it a bit harder to read, but I think the functional part (reduce with operator.mul, here) and list comprehensions seem to have a certain elegance, and they take slightly less LOC.

Excessive use of reduce, map, etc., just for the sake of it, isn't good, though. And up to 3 or so nested list comprehensions is easy to understand, IME. The thing to remember is that the nested for's (in a nested list comp) run in the same order (leftmost or outermost first) as in a nested for loop. (This is mentioned in the Python docs, and I think they did it that way to be intuitive.)

I ran the program the same way as the previous one, and it gave the same output (verified by DOS's "fc /l outfile1 outfile2", so I will not show the output again here.
#--------------------------------------------------------------
# perm_fact2.py
# Modified version of perm_fact.py, with:
# - two for loops replaced by list comprehensions;
# - recursive factorial() replaced by iterative function;
# - iterative factorial() in turn replaced by 
#   functional version, using reduce().
# Author: Vasudev Ram
# Copyright 2016 Vasudev Ram
# Web site: https://vasudevram.github.io
# Blog: http://jugad2.blotspot.com
# Product store: https://gumroad.com/vasudevram
#--------------------------------------------------------------

import sys
from itertools import permutations
from operator import mul

def num_perms_upto(n):
    return [ len(list(permutations(range(i)))) for i in range(1, n + 1) ]

def factorial(n):
    if n < 0:
        print "Argument n should be >= 0"
        sys.exit(0)
    #-------------------------------------------------------
    #Iterative computation of factorial.
    #f = 1
    #for i in range(1, n + 1):
    #    f *= i
    #return f
    #-------------------------------------------------------
    # Functional computation of factorial, using reduce().
    return reduce(mul, range(1, n + 1), 1)

def factorials_upto(n):
    return [ factorial(i) for i in range(1, n + 1) ]

print "Number of permutations of 1 .. n, where n in 1 .. 10:"
print num_perms_upto(10)
print "Factorial of n, where n in 1 .. 10:"
print factorials_upto(10)
I also timed the runs of both perm_fact.py and perm_fact2.py (and perm_fact2.py separately for both the iterative and functional versions of factorial), a few times each, but did not notice any significant difference. Sometimes one was a bit faster, sometimes the other was, sometimes nearly the same.

(One reason why I thought of timing it in the first place, was because I had read somewhere recently that using map on a sequence can be faster than processing its items in a for loop; haven't tested that, so don't know whether is right or not, but it could be - IIRC, the reason given was that the iteration then happens inside the C implementation of map, and if true, that probably holds for reduce too.)

Also, due to the small amount of code in each, and only a few iterations happening in the code, versus the size of the Python interpreter, it is likely that a good (relative) chunk of the total run time was taken by the loading and initialization of the interpreter, and maybe by parsing the .py files. Other random OS processes running on my machine could also account for the variations. Anyway, the goal here was not really to see if the changes made it faster.

- Vasudev Ram - Online Python training and consulting

FlyWheel - Managed WordPress Hosting

Get updates on my software products / ebooks / courses.

Jump to posts: Python   DLang   xtopdf

Subscribe to my blog by email

My ActiveState recipes



Thursday, September 15, 2016

Component programming in D - DDJ article by Walter Bright

By Vasudev Ram

After this post of yesterday:

Func-y D + Python pipeline to generate PDF

I was doing a search today for some D language topics, and came across this article in Dr. Dobb's Journal (DDJ) by Walter Bright, the creator of D:

Component programming in D

It's just 4 pages long, and is a good article. It talks about the motivations, principles, and techniques of component creation in D (using templates / generics, ranges, and functional programming features) and has the code for a small reusable component. He takes the reader through the process of building it up step by step.

Recommended.

- Vasudev Ram - Online Python training and consulting

Get updates on my software products / ebooks / courses.

Jump to posts: Python   DLang   xtopdf

Subscribe to my blog by email

My ActiveState recipes

FlyWheel - Managed WordPress Hosting



Sunday, October 5, 2014

Flattening an arbitrarily nested list in Python

By Vasudev Ram



A while ago, I had written this blog post:

Flatten a list of lists with a list comprehension

which talks about flattening a nested list in Python, but only for a list nested two levels deep. It was not my code - I just had seen it via Hacker News, wrote about it, and commented on an interesting property of the Python language, in the code involved. A few readers also commented on that language property.

Recently, something reminded me of my earlier post. I realized that the code in that post only worked for a list nested two levels deep. So I thought of trying to solve the problem of flattening an arbitrarily nested Python list.

Here is my attempt at the solution, in the file flatten_list2.py [1]:
# Program to flatten an arbitrarily nested list.
#flatten_list2.py
def nested_item(depth, value):
    if depth <= 1:
        return [value]
    else:
        return [nested_item(depth - 1, value)]

def nested_list(n):
    """Generate a nested list where the i'th item is at depth i."""
    lis = []
    for i in range(n):
        if i == 0:
            lis.append(i)
        else:
            lis.append(nested_item(i, i))
    return lis

def flatten(lis):
    """Given a list, possibly nested to any level, return it flattened."""
    new_lis = []
    for item in lis:
        if type(item) == type([]):
            new_lis.extend(flatten(item))
        else:
            new_lis.append(item)
    return new_lis

for n in range(0, 7):
    print n,
    lis = nested_list(n)
    print "original:", lis
    new_lis = flatten(lis)
    print "flattened:", new_lis
    print
The above program has a function called nested_list that, given an argument n, generates a list of n items, as follows: the 0th item is 0, and each succeeding item is a list nested to level i, the i'th number in the range 1 <= i < n. (See the image at the top of the post.)

The function nested_item does the work of building up the items of the outermost list, where each item (except the 0th) is a nested list. And the function flatten does the work of flattening the built-up list of nested lists.

After writing and testing my solution, I found that it works for values of n up to 998, but for n = 999 it terminates with the message "maximum recursion depth exceceded", which is to be expected, since the maximum recursion depth in Python is 1000 by default, though there is a function in the sys module to set it, called setrecursionlimit. There are two recursive functions in the program, the functions called nested_item and flatten. The flatten function causes the recursion error.

Here is the output of a sample run of my program to flatten lists:

$ flatten_list2.py
0 original: []
flattened: []

1 original: [0]
flattened: [0]

2 original: [0, [1]]
flattened: [0, 1]

3 original: [0, [1], [[2]]]
flattened: [0, 1, 2]

4 original: [0, [1], [[2]], [[[3]]]]
flattened: [0, 1, 2, 3]

5 original: [0, [1], [[2]], [[[3]]], [[[[4]]]]]
flattened: [0, 1, 2, 3, 4]

6 original: [0, [1], [[2]], [[[3]]], [[[[4]]]], [[[[[5]]]]]]
flattened: [0, 1, 2, 3, 4, 5]

orig: []
flat: []
orig: [0]
flat: [0]
orig: [0, 1]
flat: [0, 1]
orig: [0, 1, 2]
flat: [0, 1, 2]
orig: [0, 1, 2, 3]
flat: [0, 1, 2, 3]
orig: [0, 1, 2, 3, 4]
flat: [0, 1, 2, 3, 4]
I had also modified the program to try to flatten non-nested lists as a test (since it should work for those too, i.e. not change them), and that is the second section in the output above.

[1] 42 was the number of lines in my earlier version, flatten_list.py (not shown here), which I then refactored into flatten_list2.py, improving the code some in the process, and also bringing the number of lines down to 37 (not counting the second section of code, added later, that tests the flatten function on lists that are not nested).

- Vasudev Ram - Dancing Bison Enterprises

Click here to signup for email notifications about new products and services from Vasudev Ram.

Contact Page

Wednesday, March 19, 2014

Flatten a list of lists with a list comprehension

By Vasudev Ram

Recently, I saw this comment thread on Hacker News:

Python Language Features and Tricks (sahandsaba.com), which was about this post:

30 Python Language Features and Tricks You May Not Know About

One of the comments on the HN thread was this:

Except from it:

"I don't understand how this one to flatten lists works:
a = [[1, 2], [3, 4], [5, 6]]
[x for l in a for x in l]
Can somebody explain what the order of operations is here and what the variables refer to in the various stages of evaluation?"

Another HN user answered the question, and I also commented on it.

But the interesting part was where another user posted below, in the same thread, this comment:

"So that flattening can also be written as:
x = [[1,2], [3,4], [5,6]]
    [x for x in x for x in x]
"
The interesting part here (to me) was not just the use of a list comprehension to flatten the list, but the fact that the same variable is used throughout the list comprehension; in fact it is used 5 times in the expression.

I tried it out, and it works.

Then I thought of checking whether the same kind of code would work for a triply-nested list, and found that it did work:

# Flatten a list that is nested to three levels with a list comprehension.
x = [[[1,2], [3,4]], [[5,6], [7,8]]]
print "before flatten, x =", x
y = [x for x in x for x in x for x in x]
print "after flatten, y =", y

That raises the question of how the same variable name (x) can be used multiple times in the same scope to mean different things, as in the above two code fragments (for the doubly- and triply-nested lists). The explanation I can think of is that the different uses of x in the list comprehension are actually in different scopes, even though part of the same expression. Not sure if that is the right answer or not.

Update: I tried to check my explanation more by writing this - a normal for loop, not a list comprehension, which also uses the name x multiple times:
x = range(5)
for x in x:
    print x
And it worked. So it looks like my explanation (that there are different scopes) may be right, or at least close.

The HN user (jamesdutc) who posted the code with "[ x for x in x for x in x ]" has a blog here with more Python posts that look interesting:

seriously.dontusethiscode.com

Read other Python posts on my blog.

- Vasudev Ram - Dancing Bison Enterprises

Contact Page

Saturday, January 12, 2013

graph-tool. Python module for graph (networks) manipulation and display

graph-tool is a Python module for the creation, manipulation, analysis and display of graphs (the computer science data structure, not computer graphics, though it can display graphs as graphics).

I took a look at some of the code examples of graph-tool. It is fairly easy to understand and use for simple cases, e.g. there are simple library calls to create a new graph, add vertices to it, add edges between vertices, etc. Quick excerpt:

from graph_tool.all import *
g = Graph()
v1 = g.add_vertex()
v2 = g.add_vertex()
e = g.add_edge(v1, v2)
And to draw the above graph:
graph_draw(g, vertex_text=g.vertex_index, vertex_font_size=18,
output_size=(200, 200), output="two-nodes.pdf")
The above code creates this image:



It supports both directed and undirected graphs.

Though exposed as a Python module, graph-tool is internally written in C++ using the Boost Graph Library. It also makes extensive use of template metaprogramming for performance.

The graphics drawing is based on the Cairo Graphics library, which I blogged about recently.

The creator of graph-tool is Tiago de Paula Peixoto, currently a postdoc at the University of Bremen, Germany.


Vasudev Ram