Table of Contents
- From Ruby To Python, Javascript, Go
From Ruby To Python, Javascript, Go
Ruby
Python
Javascript
Go
概述
Ruby
Python
Javascript
Go
Version manager
brew install rbenv
rbenv versions
rbenv use 2.7.2
brew install pyenv
pyenv versions
pyenv global
pyenv local
yarn global add n
n
Data types
Boolean
true
false
True
False
true
false
true
false
Hash
# Hash
{a: 1, b: 2, c: 3}
# Dictionary
{'a': 1, 'b': 2, 'c': 3}
// Object
{'a': 1, 'b': 2, 'c': 3}
// ES6 Map
const mapper = new Map([['1', 'a'], ['2', 'b']]);
// Map
ages := make(map[string]int) // 不能够初始化为nil,否则不能够赋值了
ages := map[string]int{
"alice": 31,
"charlie": 34,
}
Array
arr = [1,2,3]
arr[1..] # [2, 3]
arr[-1] # [3]
arr[1..2] # [2, 3]
# 但是不支持 arr[::2]这样的操作
arr + [4, 5, 6] # [1,2,3,4,5,6]
arr = [1,2,3]
arr[1:] # [2, 3]
arr[:2] # [1, 2]
arr[::2] # [1, 3]
arr + [4, 5, 6] # [1,2,3,4,5,6]
var arr = [1,2,3]
arr.slice(0, 2) // [1, 2]
[...arr, ...arr] // [1,2,3,1,2,3]
// Go语言里面很少使用数组,因为是固定长度的。
q := [...]int{1, 2, 3}
fmt.Printf("%T\n", q) // "[3]int"
fmt.Printf("%v\n", q) // "[1,2,3]"
// 相对应的是Slice,动态序列,和Python一样,支持各种切片操作
data := []string{"one", "", "three"}
fmt.Printf("%q\n", data) // `["one" "three" "three"]`
fmt.Printf("%q\n", data[:2]) // `["one" ""]`
numbers := []int{1,2}
numbers = append(numbers, 3, 4) // [1,2,3,4]
fmt.Printf("%v\n", numbers) // "[1,2,3,4]"
Variables
Declare
Copy Array/Slice
2.6.6 :027 > a = [1,2,3]
=> [1, 2, 3]
2.6.6 :028 > b = a
=> [1, 2, 3]
>>> a = [1,2,3]
>>> b = a
>>> id(b)
4315631168
>>> id(a)
4315631168
>>> a[2] = 4
>>> a
[1, 2, 4]
>>> b
[1, 2, 4]
a := []int{1,2,3}
b := a
fmt.Printf("%v\n", a) // [1,2,3]
fmt.Printf("%v\n", b) // [1,2,3]
a = append(a, 4)
fmt.Printf("%v\n", a) // [1,2,3,4]
fmt.Printf("%v\n", b) // [1,2,3]
Control flow
If…else
if true
puts 'yes'
else
puts 'no'
end
if True:
print('yes')
elif False:
print('no')
else:
print('n/a')
if (true) {
console.log('yes');
} else {
console.log('no');
}
s := "bingo"
if s != "" {
fmt.Println("yes")
} else {
fmt.Println("no")
}
Loop
(0..10).each do |i|
puts i
end
for i in range(10):
print(i)
for i in count(start=0, step=1):
print(i)
while True:
quotient = num // output_base
remainder = num % output_base
output.append(remainder)
num = quotient
if quotient == 0:
break
let arr = ['a', 'b', 'c'];
for (let [k, v] of arr.entries()) {
console.log(k);
console.log(v);
}
let dict = {a: 1, b: 2, c: 3}
for (let [k, v] of Object.entries(dict)) {
console.log(k);
console.log(v);
}
// Only for loop in Go
sum := 1
for sum < 100 {
sum += 1
}
fmt.Println(sum)
// Infinite loop
// while true in Ruby
for {
// do something
}
// each
kvs := map[string]string{"name": "Amy", "lastName": "Amy"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
// 如果是数组,第一个就是index
arr := []string{"a", "b", "c", "d", "e"}
for i, v := range arr {
fmt.Println(i, v)
}
Methods/Functions
in general
# 在Ruby里面,函数和方法一般是同一个东西。
# 在英语里面,Function是独立的,可以调用的。Method是在类里面定义的函数,需要通过实例才可以调用它。
# 函数不是第一公民
# 这就意味着你不能够把函数赋值给变量,当作参数传入或者返回。
# 虽然可以通过symbol,或者lambda的方式来实现,但是总觉得是剑走偏锋了,一般都不这么用
# 函数是第一公民
# 在Python里面最典型的例子就是装饰器。装饰器其实就是把被修饰的函数B当做参数传入装饰器函数A,然后在返回一个新的函数C。
# 这样在执行函数B的时候,实际上是执行函数C,所以你可以在C里面定义额外的操作,比如给方法计时
# 你还可以嵌套多次装饰器,实现参数化的装饰器
// 一般没有提第一公民这事,但是的确存在
// 最显然的例子就是函数定义有两种方式,一种是函数声明,另外一种就是函数表达式
// 函数是第一公民
// 这就意味着函数可以当做值一样地处理
// 可以当作参数传入其他函数,也可以赋值给变量
// 甚至可以把一个实例的方法绑定给某个变量,调用这个变量其实就是调用这个实例的方法
p := Point{1, 2}
q := Point{4, 6}
distanceFromP := p.Distance // method value
fmt.Println(distanceFromP(q)) // "5"
// 如果你是绑定struct里面的方法,那就需要第一个参数需要指定receiver
// 就像Python里面定义方法的时候,第一个参数是`self`或者`cls`
distance := Point.Distance // method expression
fmt.Println(distance(p, q)) // "5"
类方法
# 如果理解透,其实每个类是Class的一个实例
class A
end
a = A.new # <A:0x00007fb508870018>
a.class # A
A.class # Class
# 所以,所谓的类方法,实际上其实也是实例(Class的一个实例A)方法
# 定义类方法,有好几种方法
class A
def self.m1
puts 'm1'
end
class << self
def m2
puts 'm2'
end
end
end
A.instance_eval do
def m3
puts 'm3'
end
end
module M4
def m4
puts 'm4'
end
end
# A.extend M4
# 或者像下面那样,记住隐式的self
class A
extend M4
end
# 调用的时候直接A.m1就行了
# 记住,A其实也是一个实例
class Robot {
name: string;
static availableNames: string[];
constructor() {
this.name = Robot.generateName();
}
public resetName(): void {
this.name = Robot.generateName();
}
public static releaseNames(): void {
Robot.availableNames = [];
}
public static generateName(): string {
if (
Robot.availableNames === undefined ||
Robot.availableNames.length === 0
) {
Robot.availableNames = [];
let letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
let numbers = "0123456789".split("");
for (const a of letters) {
for (const b of letters) {
for (const x of numbers) {
for (const y of numbers) {
for (const z of numbers) {
Robot.availableNames.push([a, b, x, y, z].join(""));
}
}
}
}
}
// shuffle the array list
for (let i = Robot.availableNames.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[Robot.availableNames[i], Robot.availableNames[j]] = [
Robot.availableNames[j],
Robot.availableNames[i],
];
}
}
return Robot.availableNames.pop() as string;
}
}
// https://googlechrome.github.io/samples/classes-es6/
动态方法
# method_missing
# define_method
# include / included
# prepend / prepended
# extend / extended
puts
puts 's'
print('s')
console.log('s')
s := "s"
fmt.Println(s)
sort
[3,2,1].sort => [1,2,3]
a_list = [3,2,1]
a_list.sort() # None
a_list # [1,2,3]
const arr = [
'peach',
'straw',
'apple',
'spork'
];
arr.sort()
import "sort"
strs := []string{"c", "a", "b"}
sort.Strings(strs)
fmt.Println("Strings:", strs)
ints := []int{7, 2, 4}
sort.Ints(ints)
fmt.Println("Ints: ", ints)
custom sort
[['a', 7], ['b', 2]].sort_by { |k, v| v } => [["b", 2], ["a", 7]]
# Ruby的类里面如果include了Enumerable并定义了<=>方法,那他们的实例就是可以比较的
# 具体的比较方法通过定义的<=>来实现的
# 比如下面的就是一个简单的二叉树节点的比较
class Bst
include Enumerable
attr_reader :left, :right, :data
def initialize(new_data)
@data = new_data
end
def insert(new_data)
if new_data <= @data
@left ? @left.insert(new_data) : @left = Bst.new(new_data)
else
@right ? @right.insert(new_data) : @right = Bst.new(new_data)
end
self
end
def each(&block)
return to_enum unless block_given?
@left&.each(&block)
yield @data
@right&.each(&block)
self
end
def <=>(other)
@data <=> other.data
end
def predecessor(key)
self.each_cons(2).select { |e| e.last == key }.map(&:first)[0]
end
def successor(key)
self.each_cons(2).select { |e| e.first == key }.map(&:last)[0]
end
end
>>> a = [['a', 7], ['b', 2]]
>>> a.sort(key=lambda e: (e[1], e[0]), reverse=True)
>>> a
[['b', 2], ['a', 7]]
# Python 好像不屑于Ruby的spaceship operator
# 如果需要排序,用自定义排序就可以搞定了
// 如果记得Ruby中的宇宙飞船符的话,下面的通过函数自定义排序其实也是类似的
var items = [
{ name: 'Edward', value: 21 },
{ name: 'Sharpe', value: 37 },
{ name: 'And', value: 45 },
{ name: 'The', value: -12 },
{ name: 'Magnetic', value: 13 },
{ name: 'Zeros', value: 37 }
];
// sort by value
items.sort(function (a, b) {
return a.value - b.value;
});
// sort by name
items.sort(function(a, b) {
var nameA = a.name.toUpperCase(); // ignore upper and lowercase
var nameB = b.name.toUpperCase(); // ignore upper and lowercase
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
});
// Need to implement sort.Interface - Len, Less, and Swap on type byLength
type byLength []string
func (s byLength) Len() int {
return len(s)
}
func (s byLength) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s byLength) Less(i, j int) bool {
return len(s[i]) < len(s[j])
}
func main() {
fruits := []string{"peach", "banana", "kiwi"}
sort.Sort(byLength(fruits))
fmt.Println(fruits)
}
shift/unshift/pop/push
arr = [] # => []
arr.push(1) # => [1]
arr.unshift(2) # => [2, 1]
arr.shift # => 2
arr.pop # => 1
arr = []
arr.append(1)
arr.insert(0, 2) # => [2, 1]
arr.pop(0) # => 2
arr.pop() # => 1
var arr1 = [0, 1, 2]
arr1.push(3)
var arr2 = [4, 5, 6]
arr1.push(...arr2)
arr1.pop()
arr1.shift()
// go 没有pop方法,只能够自己写
func pop(alist *[]int) int {
f:=len(*alist)
rv:=(*alist)[f-1]
*alist=append((*alist)[:f-1])
return rv
}
func main() {
n:=[]int{1,2,3,4,5}
fmt.Println(n)
last:=pop(&n)
fmt.Println("last is",last)
fmt.Printf("list of n is now %v\n", n)
}
regex
'13243432432'.scan(/\d/) => ["1", "3", "2", "4", "3", "4", "3", "2", "4", "3", "2"]
m = /\A(\d{3})(\d)/.match('13243432432') => #<MatchData "1324" 1:"132" 2:"4">
m[0] # "1324"
m[1] # "132"
import re
re.findall(r'\d', '1234232432')
# ['1', '2', '3', '4', '2', '3', '2', '4', '3', '2']
import re
s = 'a1b2c3'
s = 'a1b#2c3'
m = re.match(r'([^#]*)#(.*)', s)
m.group() # => 'a1b#2c3'
m.group(1) # => 'a1b'
m.group(2) # => '2c3'
const regex = /[a-zA-Z]/g;
const matched_chars = 'abcdefg'.match(regex);
// ['a', 'b', 'c', 'd', 'e', 'f', 'g']
find
lst.find { |e| e == i }
next(x for x in seq if predicate(x))
const array1 = [5, 12, 8, 130, 44];
const found = array1.find(element => element > 10);
// 12
concat two arrays
[1,2,3] + [4, 5, 6]
b = [1,2,3]
b.extend([5,4,6])
b + [7,8,9]
var a = [1,2,3]
// don't use + as it will return '1,2,34,5,6'
a.push(...[4,5,6])
a //[1,2,3,4,5,6]
id
a.object_id
id(a)
// no such method
class
'str'.class
type('123')
'123'.__class__
var a = '1,2,3'
a.__prop__.constructor
Javascript
详见继承关系
uniq
[1,1,1].uniq => [1]
list(set([1,1,1]))
let arr = [1,2,3,1,2,3]
[...new Set(arr)]
// [1, 2, 3]
map
[1,2,3].map { |e| e * 3 }
list(map(lambda x: x * 3, [1,2,3]))
[i * 3 for i in [1,2,3]]
[1,2,3,4,5].map( x => x * 2);
select > filter
(-5..5).select { |x| x < 0 }
less_than_zero = list(filter(lambda x: x < 0, range(-5, 5)))
[e for e in range(-5, 5) if e < 0]
Array.from({length: 5}, (v, i) => i).filter( x => x % 2 === 0);
// [0, 2, 4]
reduce
[1,2,3].reduce(0) { |sum, x| sum + x }
from functools import reduce
reduce(lambda sum, x: sum + x, [1,2,3], 0)
const array1 = [1, 2, 3, 4];
array1.reduce((sum, x) => sum + x);
all
[1,2,3].all { |e| e.even? }
all(len(g) % 2 == 0 for g in groups)
[2,4,6].every( x => x % 2 === 0)
any?
[1,2,3].any? { |e| e > 1 } => true
any(x > 3 for x in [1,2,3]) # False
[2,4,6].some( x => x % 2 === 0)
merge
a = {name: 'phx', age: 12}
a.merge({gender: 'male'})
In [51]: a = {'name': 'phx', 'age': 12 }
In [52]: a
Out[52]: {'name': 'phx', 'age': 12}
In [53]: a.update({'gender': 'male'})
In [54]: a
Out[54]: {'name': 'phx', 'age': 12, 'gender': 'male'}
var a = { a: 1 }
var b = Object.assign(a, { b: 2 })
// {a: 1, b: 2}
group_by > Counter
[1,2,3,4,5,6,7,1,3].group_by {|e| e}.map { |k, v| [k, v.size]}.to_h
import collections
dict(collections.Counter([1,2,3,4,5,6,7,1,3]))
[1,2,3,4,5,6,7,1,3].reduce((acc, x) => {
if (!acc[x]) acc[x] = 0;
acc[x] += 1;
return acc;
}, {});
range
(1..5).to_a
list(range(10))
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list(range(1, 10))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Array.from({length: 5}, (v, i) => i);
// [0, 1, 2, 3, 4]
chars
'foo'.chars
[char for char in 'foo']
Array.from('foo')
with
Interface
// 接口类型 抽象的类型。对应到Python的ABCMeta和@abstractmethod。不会暴露对象内部值的结构,只会暴露自己的方法。
Exception Handle
begin
1/0
rescue Exception => e
p e
end
try:
y = ALPHABET.index(char)
except ValueError:
return char
Dynanmic methods
self.send(k)
getattr(self, k)()
Others
List all small characters
('a'..'z').to_a
from string import ascii_lowercase
ALPHABET = list(ascii_lowercase)
concat list
[1,2,3].join('')
''.join([1,2,3])
[1,2,3].join('')
Convert number to binary
7.to_s(2)
"{0:b}".format(7 % 256)
10..toString(2)
Convert binary to number
'101'.to_i(2)
int('101', 2)
parseInt('101', 2)
transalate
"hello".tr('el', 'ip') #=> "hippo"
"hello".tr('aeiou', '*') #=> "h*ll*"
"hello".tr('aeiou', 'AA*') #=> "hAll*"
ALPHABETS = list(chr(x) for x in range(ord('a'), ord('z')+1))
TRANSLATION_TABLE = str.maketrans(''.join(ALPHABETS), ''.join(reversed(ALPHABETS)))
[ch.translate(TRANSLATION_TABLE) for ch in 'aeiou']
permutations
(1..3).to_a.permutation(2).to_a
=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
>>> [i for i in itertools.permutations([1,2,3], 2)]
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
zip
a = [ 4, 5, 6 ]
b = [ 7, 8, 9 ]
[1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
[1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]]
a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
# Python code to demonstrate the working of
# zip()
# initializing lists
name = [ "Manjeet", "Nikhil", "Shambhavi", "Astha" ]
roll_no = [ 4, 1, 3, 2 ]
marks = [ 40, 50, 60, 70 ]
# using zip() to map values
mapped = zip(name, roll_no, marks)
# converting values to print as set
mapped = set(mapped)
# printing resultant values
print ("The zipped result is : ",end="")
print (mapped)
unzip
# unzipping values
namz, roll_noz, marksz = zip(*mapped)
print ("The unzipped result: \n",end="")
# printing initial lists
print ("The name list is : ",end="")
print (namz)
sleep
sleep 1
import time
time.sleep(2)
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
console.log("Hello");
sleep(2000).then(() => { console.log("World!"); });
format
"%02d:%02d" % exact_time
format("%02d", 7) #有点不像ruby代码耶
'{:02d}:{:02d}'.format(7, 8)
delete
'{:02d}:{:02d}'.format(7, 8)
replace
'{:02d}:{:02d}'.format(7, 8)
template
'{:02d}:{:02d}'.format(7, 8)
Not supporting method chaining
I have a string and need to convert it to ascii codes. That should be done via map
. Later, I want to sum the values, thing will be different in ruby
and python
.
'abcd'.to_a.map { |e| e.bytes }.sum
sum(map(lambda x: ord(x), list('abcd')))
In above example, you could achieve the purpose by simply add .method
to convert the previous result into a new format in ruby
. However, you need to wrap another function like sum()
to achieve this. IMHO, this is not easy for human reading. You need to figure out the flow from inside to outside, that’s list
> map
> sum
.
Return data
By default, python
return None
unless you specify the return value. ruby
will return the last value of the method. A simple example is sort()
returns None
, while .sort
returns sorted array/list.