Archive
Array min, max with Coffeescript
Quite simple actually:
Array::max=-> Math.max.apply(null, this) Array::min=-> Math.min.apply(null, this) a=[6, 5, 17, -3, 4.5] console.log a.max() console.log a.min()
Outputs:
17
-3
Calling initialization function only once with this js trick
There are times when an initialization function in a js object needs to be called only once. Here’s one of the solutions I came up with. When F.paint() is called, a check on the initialization tag (need_init) is performed. need_init remains undefined until init() is called for the first time.
The code:
var F=(function() {
var self=this;
var init=function() {
console.log('Initialized.');
self.need_init=false;
}
return {
paint: function() {
if(typeof self.need_init==='undefined') {
init();
}
console.log('Now I am ready to paint.');
}
};
})();
F.paint();
F.paint();
F.paint();
Output from the above example:
Initialized.
Now I am ready to paint.
Now I am ready to paint.
Now I am ready to paint.
Enjoy coding.
PHP: removed trailing zeros from numeric strings (code illustration)
<?php
$nums=array('1.0', '2.300', '4', '5.9000');
echo "Original format:\n";
foreach($nums as $num) {
echo "$num\n";
}
echo "\nTrailing zeros removed:\n";
foreach($nums as $num) {
echo ($num+0)."\n";
}
Output:
Original format:
1.0
2.300
4
5.9000
Trailing zeros removed:
1
2.3
4
5.9
Learning CoffeeScript
Practice 1: Define a Student class, make some new instances and classify them into two arrays based on the student scores
class Student
constructor:(@gender, @score)->
s1=new Student('M', 45)
s2=new Student('F', 78)
s3=new Student('F', 59)
s4=new Student('M', 99)
passed=[]
failed=[]
(if s.score>59 then passed else failed).push s for s in [s1, s2, s3, s4]
console.log passed
console.log failed
Practice 2: Array filtering
pr=(items, lbl)->
console.log "==#{lbl}=="
for item, i in items
console.log "Item #{i}: #{item}"
false
a=[1..9]
odd=(item for item in a when item%2)
even=(item for item in a when item%2==0)
double=(item*2 for item in a)
pr odd, "odd"
pr even, "even"
pr double, "double"
Practice 3: more about class
class Candidate
constructor:(@approval_rate)->
class Election
elect:(candidate)->
candidate.approval_rate>0.5
e=new Election
console.log e.elect( new Candidate(0.34) )
console.log e.elect( new Candidate(0.59) )
Practice 4: serial_maker (based on
JavaScript: The Good Parts by Douglas Crockford Chap 4.12)
class SerialMaker
constructor:(@prefix='Q', @start=0)->
gen_seq:()->
@start+=1
@prefix+@start
sm=new SerialMaker('SQ')
console.log sm.gen_seq()
console.log sm.gen_seq()
console.log sm.gen_seq()
Practice 5: (added 7/12/2012) Self-invoking constructor
class Person
constructor:(name='no name')->
return new Person(name) if !(@ instanceof Person)
@name=name
id:->
return @name
isrich:true
p1=Person('Freedom')
# or the above line can be written as
# p1=new Person('Freedom')
# the result is exactly the same and the
# benefit is user doesn't need to worry about forgetting using the "new" keyword
console.log p1.id() + ','+ p1.isrich
Reference: http://arcturo.github.com/library/coffeescript/index.html
Javascript OOP design pattern
I’ve been using the following programming pattern whenever I need to write some client-side javascript:
( function() {
if(!window.Foo) window.Foo={};
function some_priv_func() {
// define a private function (not accessible from
// outside of the enclosure)
alert('this is a private function');
}
function some_pub_func() {
// calling some_priv_func()
some_private_func();
}
window.Foo.some_pub_func=some_pub_func;
} )();
In the above example I create a Foo object and expose one function some_pub_func, which can be invoked by calling Foo.some_pub_func(). Enclosure is used to avoid name-space conflicts. It’s worth noting that the some_priv_func can not be accessed from outside of the enclosure.
I recently discovered a better way to program the OOP way in Jtavascript through Hands-on Node.js (page 100) and I would like to share with you this technique. Let’s look at code:
( function() {
if(!window.Foo2) {
window.Foo2=function(options) {
// to avoid getting confused when using
// 'this' in member functions
var self=this;
self.options=options;
function some_priv_func() {
// define a private function (not accessible from
// outside of the enclosure)
alert('this is a private function');
}
self.some_pub_func=function() {
// calling some_priv_func()
some_priv_func();
}
};
window.Foo2.create=function(options) {
return new Foo2(options);
}
}
} )();
Foo2.create() is made so one can initialise a Foo2 instance without using the “new” keyword. You can use Foo2 in ways like the following:
var f2=new Foo2( { name: 'the new guy' } ); // as if Foo2.create doesn't exist
or
var f2=Foo2.create( { name: 'the new guy' } );
For demonstration purpose I also expose the member options to the public allowing it be accessed and changed. A better way to handle this is to use the jQuery extend function. (Assuming jQuery is being used)
...
var self=this;
var defaults={
name: 'no name'
};
// merge settings in options to defaults
$.extend(defaults, options);
function some_priv_func() {
...
So if one initialises Foo2 without any options ( var f2=Foo2.create() ), defaults will have its default value {name: ‘no name’}. Or it can be overwritten by providing a parameter.
The benefit of this is the exposing of member options (using defaults instead, which is not accessible outside of Foo2) is avoided.
Print color in shell terminal
Sometimes you might want to print something with color in a text terminal (by color I mean something other than the default text color). Put the following shell function to your ~/.bash_profile and you are go to good.
cecho() {
case $2 in
red) code=31;;
blue) code=34;;
green) code=32;;
cyan) code=36;;
purple) code=35;;
brown) code=33;;
white) code=37;;
*) code=30;;
esac
printf "\e[01;${code}m$1\e[0m\n"
}
Some examples:
cecho hello cyan cecho "something needs your attention" brown cecho "there's something terribly wrong, have to abort now" red cecho "this looks so pale" white cecho "will purple work too?" purple cecho goodbye blue
The above commands should output something like this ($TERM setting xterm-256color, tested on both OS X 10.7.2 and Ubuntu 11.10 64bit Server):

Build a simple PHP template with str_replace()
You are given a task to notify a list of customers regarding their pin setting changes through their email address on file. There are many ways to accomplish this in PHP. One way I found quite interesting is through a simple php function str_replace. Let me demo through the following example (only showing how the message body is constructed, the email address part should be easy to take care of):
<?php
/* main.php */
function build_key($key) {
return '{{'.$key.'}}';
}
function gen_msg($format_str, $arr) {
$keys=array_map(build_key, array_keys($arr));
// $keys can also be generated by using the following code
// but I found using array_map is more elegant and fun
// $keys=array();
// foreach(array_keys($arr) as $k) {
// array_push($keys, '{{'.$k.'}}');
// }
return str_replace( $keys, array_values($arr), $format_str);
}
// here's the template
$template="Dear {{user}}, your pin number has been changed to {{pin}}.";
// here's the data, hard-coded in this example but it can be pulled from external sources as well
$data=array(
array( 'user'=>'John Smith', 'pin'=>'1234' ),
array( 'user'=>'Mr. S', 'pin'=>'9999' ),
array( 'user'=>'Customer', 'pin'=>'****' )
);
foreach($data as $d) {
printf("%s\n", gen_msg($template, $d));
}
Run the above code through php (cli) will output the following:
Dear John Smith, your pin number has been changed to 1234.
Dear Mr. S, your pin number has been changed to 9999.
Dear Customer, your pin number has been changed to ****.
[ Update ] I also added an OOP implementation of the above code, if you are interested you can checkout my code on github.
Combine regular expression and conditional statements in BASH
As we all know we can use conditional statements in BASH. For example, show usage if number of arguments is 0:
#!/usr/bin/env bash
if [ $# -eq 0 ]; then
echo "Usage: $0 start|stop|restart"
exit 0
fi
echo "going to run with \$1=$1"
We might also want to use regular expression to test if $1 is start, stop or restart if $# is no longer 0:
#!/usr/bin/env bash
function usage() {
echo "Usage: $0 start|stop|restart"
}
if [ $# -eq 0 ]; then
usage
exit 0
fi
if [[ ! $1 =~ ^(start|stop|restart)$ ]]; then
usage
exit 0
fi
echo "going to run with \$1=$1"
But wouldn’t it be nice if the tests can be combined together. With bash operator || the above code can be written as:
#!/usr/bin/env bash
function usage() {
echo "Usage: $0 start|stop|restart"
}
if [ $# -eq 0 ] || [[ ! $1 =~ ^(start|stop|restart)$ ]]; then
usage
exit 0
fi
echo "going to run with \$1=$1"
One more example using operator && instead:
#!/usr/bin/env bash
if [ -d ~/a_folder ] && [[ $1 =~ ^(install|remove)$ ]]; then
echo "going to $1 something"
else
echo "Folder ~/a_folder doesn't exist or you specified the wrong parameter:"
echo "Usage: $0 install|remove"
exit 0
fi
MySQL: select data whose certain column contains the specified values only
This problem could be best described by an example as below:
select * from mytbl; +------+------+ | k | v | +------+------+ | A | 1 | | A | 2 | | A | 3 | | B | 1 | | B | 3 | | C | 1 | | C | 3 | | C | 4 | | E | 2 | | E | 1 | | F | 5 | +------+------+
k, v are both char(10), not null.
I want to find out records whose v column is either 1 or 3 [and only 1 or 3, therefore in the above example the only qualified records are ('B', '1') and ('B', '3')]. This is just a simplified version of the problem I faced at work recently and I did find someone posting the similar question on Internet but I forgot to bookmark the url and I didn’t find its solutions interesting hence I pulled my hair a bit and came up with the following solution using group_concat and regexp:
select k, group_concat(distinct v order by v) as g from mytbl group by k having g regexp '^(1,?)?(3)?$'; +------+------+ | k | g | +------+------+ | B | 1,3 | +------+------+
If the requirement becomes v is either 1, 3 or 4 (again, 1, 3 or 4 only),
select k, group_concat(distinct v order by v) as g from mytbl group by k having g regexp '^(1,?)?(3,?)?(4)?$'; +------+-------+ | k | g | +------+-------+ | B | 1,3 | | C | 1,3,4 | +------+-------+
Play with randomness in MySQL
Some of you might know about the rand() function in MySQL — it randomly generates float point number between 0 and 1. Most of the time we use it to generate results that we want to be in random order. For example,
We have a people table that has the following records:
select * from people; +-----------+ | name | +-----------+ | Bob | | Alice | | Kim | | Tom | | Jerry | | Linda | | Fransisco | | Zack | | Peter | +-----------+
We are going to pick 3 persons out of the list randomly, so we do a
mysql> select * from people order by rand() limit 3; +------+ | name | +------+ | Zack | | Bob | | Kim | +------+
The above query should return (most likely) different result every time. Next I am going to make it a little more interesting. Let’s say I have another table named prize which contains a list of prizes:
select * from prize; +-----------------+ | name | +-----------------+ | Pencil | | Coffee grinder | | iPad | | GPS watch | | Yoga mat | | 2 movie tickets | +-----------------+
What we want to do is to assign a randomly picked prize to each person in the people table (assuming the same prize can be assigned to more than one person as there are fewer number of prizes than number of people), here’s the query
select o.*, (select name from prize order by rand() limit 1) as prize from people o;
This would return something like the following (again the result will be most like different if you try it):
+-----------+-----------------+ | name | prize | +-----------+-----------------+ | Bob | iPad | | Alice | Yoga mat | | Kim | GPS watch | | Tom | GPS watch | | Jerry | iPad | | Linda | GPS watch | | Fransisco | Pencil | | Zack | 2 movie tickets | | Peter | GPS watch | +-----------+-----------------+
For your convenience you can use the following sql statements to generate the tables with data populated:
CREATE TABLE `people` (
`name` varchar(30) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `people` VALUES ('Bob'),('Alice'),('Kim'),('Tom'),('Jerry'),('Linda'),('Fransisco'),('Zack'),('Peter');
CREATE TABLE `prize` (
`name` varchar(50) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `prize` VALUES ('Pencil'),('Coffee grinder'),('iPad'),('GPS watch'),('Yoga mat'),('2 movie tickets');