Saturday, February 24, 2007

Attribute mapper in Python

I really don't like redundancy. Mainly it's not about the kind that just makes you type more when you program. It's about concepts, having to think about some trivial stuff each and every time and not being able to perfectly focus on the task at hand. Many minor disturbances can have a nasty result (maybe just on the fun part).
I dislike programming patterns that use looping variables just because 'this is the standard way to do it'. Even functional iteration is in some cases redundant.
Some examples in python:

Do a map on list:

[fn(var) for var in list]


Here var is pretty redundant. Map is more concise:

map(fn, list)

But, when it comes to taking some attribute/calling a function on every element of a list, things get ugly for map,

map(lambda var: var.attribute, list)

but stay about the same for the list comprehension:

[var.attribute for var in list]

Something as concise as the first expression of map for attributes would be a welcome. Expressing it in python:

mapper(list).attribute

'.' is used to take the attribute because it's shorter than using a string attribute and is more intuitive.

A possible implementation:

class mapper(list):
def __getattr__(self, attr):
list.__init__(self, [getattr(x, attr) for x in self])
return self

def __call__(self, *args, **kws):
list.__init__(self, [x(*args, **kws) for x in self])
return self

Here you cannot use attributes that are methods in the list class.
The advantage can be noticed for accessing attributes that don't have a functional accesor (ie lambda x: x.attribute).

Examples of use:

mapper("aBcD").lower()
==> ['a', 'b', 'c', 'd']

class a: a = 1

mapper([a() for x in range(3)]).a
==> [1, 1, 1]

Other uses (call every function in a list):

mapper([lambda:1,lambda:2])()
==> [1, 2]

mapper("ab ac bc".split()).replace('a','x').capitalize()
==> ['Xb', 'Xc', 'Bc']

Wednesday, February 21, 2007

More than List Comprehensions. Common Lisp Loop

Now, here I was admiring list comprehensions in other languages but lisp. It seams the loop macro is more than it looks. List comprehensions are an iterative style combination of map and filter constructs. Well, with loop in lisp you can do even more. You can actually include reduce in the picture.

A helper macro to shorten our code ;) :

(defmacro for(&body body)
    `(loop for ,@body))


A small function builder that integrates reduce into loop:

(defun loop-reduce (fn)
    (lambda (l)
        (when (cdr l)
            (cons (funcall fn (car l) (cadr l))
                        (cddr l)))))

Here are the basic implementations of these three function in the loop sub-language:

Two nested maps (applied function is list):

(for x below 3 nconc
    (for y below 3 collect
        (list x y)))

and the result:
((0 0) (0 1) (0 2) (1 0) (1 1) (1 2) (2 0) (2 1) (2 2))

A simple filter (applied function is oddp):

(for x below 10 when (oddp x) collect x)

with the result:
(1 3 5 7 9)

And finally a reduce (applied function is +):

(for x in '(1 2 3 4) by (loop-reduce #'+) finally (return x))

with the result:
10

If you do:

(for x in '(1 2 3 4) by (loop-reduce #'+) collect x)

you also get the intermediary results:
(1 3 6 10)

Well, the last reduce could have been a lot easier written as:
(for x in '(1 2 3 4) sum x)
but this isn't that general (even if it works also with counting, minimizing, maximizing).

Now, isn't that nice :P

Sunday, February 18, 2007

docs.google.com

Just used a very nice feature of google docs. I was wondering for some time (just wondering not actually thinking about it) how I could make that post text box larger. And there it was all the time. Google docs offers easy integration with lots of other blog hosts.

Monday, February 05, 2007

Problems with the hard disks

Lately I've been having problems with my hard-drives. I had 2 SATA drives on a stripped RAID array and one of them broke. Here's what I did in not exactly the same order to recover my data. I'm no expert but maybe this can help somebody.

1. Check the drives with the Windows install disk (it couldn't have seen the partitions right)

2.
Check the drives with a Linux install disk (Ubuntu, Knoppix or could have used Fedora's). No big difference using "fdisk -l" to see the partitions correctly.

3. Download "Ultimate Boot CD" [http://www.ultimatebootcd.com] and burn it on a CD. You can get a basic version and a full version that also has a Linux based OS and some more programs that you can use to check disks/partitions and some other good stuff (like antiviri).
UBCD has some built-in firmware programs for physically checking your hard-disk. Use these to repair partition/fix bad sectors if possible.
If all fails try moving your hdd to a Windows system /adding a good hdd to your system and installing Windows. Next:

4. Use Partition Magic to check your hdd. If you don't care about the data on the disk fully-format your drive:
- right click on the drive to enable bad sector checking
- recreate/create partitions to fill the disk and format them
There's a bug with bad partition info in Partition Magic 8 that makes the program fail to start so use Paragon Hard Disk Manager to repartition a disk.
You can also use the Windows chkdsk or Norton System Works - Disk Doctor to check/fix the drive.

5. If the data on the disk matters to you use Get Data Back [http://www.runtime.org/gdb.htm]. If you have a broken stripped RAID try RAID Reconstructor [http://www.runtime.org/raid.htm] first to un-strip the disk first.

6. If finally you find that you have a completely unusable disk drop it and buy another. Else, try using a disk monitor like HDD Health [http://www.panterasoft.com] to notice any problems before they become too serious. This is especially nice with the SMART option enabled on the drive.

Finally I wasn't successful because the damage to one of my drives was too great.