Hiển thị các bài đăng có nhãn Lập trình. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Lập trình. Hiển thị tất cả bài đăng

Thứ Tư, 11 tháng 2, 2009

Communicating with code

Some people can sell their ideas with a brilliant speech or a slick powerpoint presentation.

I can't.

Maybe that's why I'm skeptical of ideas that are sold via brilliant speeches and slick powerpoints. Or maybe it's because it's too easy to overlook the messy details, or to get caught up in details that seem very important, but aren't. I also get very bored by endless debate.

We did a lot of things wrong during the 2.5 years of pre-launch Gmail development, but one thing we did very right was to always have live code. The first version of Gmail was literally written in a day. It wasn't very impressive -- all I did was take the Google Groups (Usenet search) code (my previous project) and stuff my email into it -- but it was live and people could use it (to search my mail...). From that day until launch, every new feature went live immediately, and most new ideas were implemented as soon as possible. This resulted in a lot of churn -- we re-wrote the frontend about six times and the backend three times by launch -- but it meant that we had direct experience with all of the features. A lot of features seemed like great ideas, until we tried them. Other things seemed like they would be big problems or very confusing, but once they were in we forgot all about the theoretical problems.

The great thing about this process was that I didn't need to sell anyone on my ideas. I would just write the code, release the feature, and watch the response. Usually, everyone (including me) would end up hating whatever it was (especially my ideas), but we always learned something from the experience, and we were able to quickly move on to other ideas.

The most dramatic example of this process was the creation of content targeted ads (now known as "AdSense", or maybe "AdSense for Content"). The idea of targeting our keyword based ads to arbitrary content on the web had been floating around the company for a long time -- it was "obvious". However, it was also "obviously bad". Most people believed that it would require some kind of fancy artificial intelligence to understand the content well enough to target ads, and even if we had that, nobody would click on the ads. I thought they were probably right.

However, we needed a way for Gmail to make money, and Sanjeev Singh kept talking about using relevant ads, even though it was obviously a "bad idea". I remained skeptical, but thought that it might be a fun experiment, so I connected to that ads database (I assure you, random engineers can no longer do this!), copied out all of the ads+keywords, and did a little bit of sorting and filtering with some unix shell commands. I then hacked up the "adult content" classifier that Matt Cutts and I had written for safe-search, linked that into the Gmail prototype, and then loaded the ads data into the classifier. My change to the classifier (which completely broke its original functionality, but this was a separate code branch) changed it from classifying pages as "adult", to classifying them according to which ad was most relevant. The resulting ad was then displayed in a little box on our Gmail prototype ui. The code was rather ugly and hackish, but more importantly, it only took a few hours to write!

I then released the feature on our unsuspecting userbase of about 100 Googlers, and then went home and went to sleep. The response when I returned the next day was not what I would classify as "positive". Someone may have used the word "blasphemous". I liked the ads though -- they were amusing and often relevant. An email from someone looking for their lost sunglasses got an ad for new sunglasses. The lunch menu had an ad for balsamic vinegar.

More importantly, I wasn't the only one who found the ads surprisingly relevant. Suddenly, content targeted ads switched from being a lowest-priority project (unstaffed, will not do) to being a top priority project, an extremely talented team was formed to build the project, and within maybe six months a live beta was launched. Google's content targeted ads are now a big business with billions of dollars in revenue (I think).

Of course none of the code from my prototype ever made it near the real product (thankfully), but that code did something that fancy arguments couldn't do (at least not my fancy arguments), it showed that the idea and product had real potential.

The point of this story, I think, is that you should consider spending less time talking, and more time prototyping, especially if you're not very good at talking or powerpoint. Your code can be a very persuasive argument.

The other point is that it's important to make prototyping new ideas, especially bad ideas, as fast and easy as possible. This can be especially difficult as a product grows. It was easy for me to stuff random broken features into Gmail when there were only about 100 users and they all worked for Google, but it's not so simple when there are 100 million users.

Fortunately for Gmail, they've recently found a rather clever solution that enables the thousands of Google engineers to add new ui features: Gmail Labs. This is also where Google's "20% time" comes in -- if you want innovation, it's critical that people are able to work on ideas that are unapproved and generally thought to be stupid. The real value of "20%" is not the time, but rather the "license" it gives to work on things that "aren't important". (perhaps I should do a post on "20% time" at some point...)

One of the best ways to enable prototyping and innovation on an established product is though an API. Twitter is possibly the best example of how well this can work. There are thousands of different Twitter clients, with new ones being written every day, and I believe a majority of Twitter messages are entered though one of these third-party clients.

Public APIs enable everyone to experiment with new ideas and create new ways of using your product. This is incredibly powerful because no matter how brilliant you and your coworkers are, there are always going to be smarter people outside of your company.

At FriendFeed, we discovered that our API does more than enable great apps, it also reveals great app developers. Gary and Ben were both writing FriendFeed apps using our API before we hired them. When hiring, you don't have to guess which people are "smart and gets things done", you can simply observe it in the wild :)

In my previous post, I asked people to describe their "ideal FriendFeed". Since then, I've been thinking about ideas for my "ideal FriendFeed". Unfortunately, it's very difficult for me to know how much I like an idea based only on words or mockups -- I really need to try it out. So in the spirit of prototyping, I've used my spare time to write a simple FriendFeed interface that prototypes some of the things I've been thinking about. This interface isn't the "future of FriendFeed", it's just a collection of ideas, some that I like, and some that I don't. One thing that's kind of cool about it (from a prototyping perspective) is that it's written entirely in Javascript running in the web browser -- it's just a single web page that uses FriendFeed's JSON APIs to fetch data. This also means that it's relatively easy for other people to copy and change -- you don't even need a server!

Trích blog Paul Buchheit

------------------------------------------------------------------------------
Resume by TuanNM : có những ý tưởng dường như rất với vẩn, nhưng khi implemented lại rất tuyệt vời, ngược lại, cũng có những idea rất tuyệt vời cho đến khi bạn chạy thử nó. Hãy cố gắng implement your idea as soon as possible, đối với các innovation app, đừng quá câu nệ thiết kế ..., việc viết lại code là chuyện hết sức bình thường. Chính tôi đã phạm sai lầm này :(.

Thứ Ba, 3 tháng 2, 2009

Các module, thủ tục có thể sử dụng trong nhiều dự án khác của GTID

Những module có thể tái sử dụng với những dự án khác nhau. Đây là nơi tổng hợp những module có tính tái sử dụng cao, có thể sử dụng trong nhiều dự án, chúng ta sẽ cập nhật theo thời gian, để các team khác biết, tránh thực hiện code lại những ji đã code và test rồi.
- Module phục vụ suggestion C# phía server và JS phía client(giống kiểu các SearchEngine trả về các gợi ý realtime khi ta đánh query), trả về danh sách string tương ứng với một đoạn string đầu vào. Module này đã dc viết khá tối ưu, với độ phức tạp hằng số, hoàn toàn có thể thích ứng với cả danh sách hàng triệu string mà ko vấn đề gì.

- Những thao tác phổ biến trên Array, List viết trên C#, viết dưới dạng template, có tính tái sử dụng cao, các dự án dùng C# khác sẽ ko phải code lại những hàm này :

  • Tìm kiếm nhị phân trên Array, List đã sắp xếp tăng dần rồi.
  • Hàm chèn một phần tử vào một danh sách đã sắp xếp mà vẫn bảo toàn tính sắp xếp của nó.
  • Hàm xác định vị trí để insert 1 phần tử vào một danh sách tăng dần.
  • ...

- Module xác định nước truy cập của user bằng C#, dùng khi ta muốn biết một user truy cập website của mình thuộc nước nào.

- Module quản lí tree, và forest với relation database, sử dụng giải thuật MPTT viết bằng C#, support các hầu hết thao tác cơ bản trên tree hay forest như tìm các tổ tiên, con cháu của 1 hoặc 1 nhóm node, thay đổi parent, xóa đi một node ... Giải thuật MPTT cho phép quản lí tree/forest có kích thước lớn với cơ sở dữ liệu quan hệ.

- Module counter, bộ đếm số người truy nhập trang web => có module sẵn rồi, ko phải code chức năng này.

- Module nhận feedback của người dùng, đã có sẵn, tích hợp với tool bugtracking, ko cần code module này trong mọi dự án bất kể ngôn ngữ hay platform, trừ khi chúng ta ko có trách nhiệm nhận feedback của user đối với dự án đó.

(tiếp tục cập nhật theo thời gian).

Thứ Tư, 28 tháng 1, 2009

Sử dụng Delegate trong lập trình

Bên cạnh Generic Programming (Template Programming), thì Delegate cũng là một trong advanced technique trong lập trình C#. Lần trước tôi đã giới thiệu mọi người Generic Programming, lần này tôi xin giới thiệu Delegate trong C#, trong Java chưa có kỹ thuật tương tự. Nếu biết tận dụng delegate, việc code sẽ trở nên tổng quát hơn, ngắn gọn hơn, tính tái sử dụng tăng cao, và performance giảm ko đáng kể.
Hiểu một cách đơn giản, Delegate tương tự như con trỏ hàm trong C++, nó là con trỏ hàm bởi nó có thể trỏ vào các hàm khác nhau (nếu các hàm đó có cùng giao diện), và người ta có thể gọi một hàm thông qua con trỏ hàm, bằng cách cho con trỏ hàm trỏ vào hàm đó, và call con trỏ hàm cũng tương đương việc call hàm được con trỏ hàm trỏ đến.

Khai báo delegate, chú ý delegate ngang hàng với khai báo class tương tự enum và struct, hãy khai báo delegate bên ngoài class, ex :

public delegate int Compare(int inA, int inB);

Hoặc tốt nhất là khai báo khai báo dạng template, tăng tính tái sử dụng.

public delegate int Compare<T>(T inA, T inB);
public delegate int Compare<T, E>(T inA, E inB);

public delegate T DFunc0Para<T>();
public delegate T DFunc1Para<E, T>(E x);
public delegate T DFunc2Para<E, F, T>(E x, F y);
public delegate void DProc1Para<E>(E x);
public delegate void DProc2Para<E, F>(E x, F y);

Giao diện một delegate sẽ đại diện cho các hàm mà delegate này có thể trỏ tới, gồm kiểu trả về và danh sách tham số, còn tên delegate hay tên hàm ko quan trọng.

Khai báo một biến có kiểu Delegate :

Compare<string> compare;

Thực hiện trỏ một delegate tới một hàm, ex :

compare = Compare;

Call một hàm thông qua delegate :

compare("heno", "hi");

Ví dụ đơn giản :

// ham dc khai bao de cho delegate tro toi
private int CompareFunc(string x, string y)
{
return x.CompareTo(y);
}
public void testDelegate()
{
// khai bao bien kieu Delegate
Compare<string> compare;

// thuc hien tro bien delegate den ham Compare ben tren,
// giao dien cua ham va Delegate phai tuong thich thi moi tro dc

compare = CompareFunc;

// thuc hien call delegate
int val = compare("heno", "hi");
}

Một số ví dụ sử dụng delegate :
- List.RemoveAll và List.ConvertAll : List là lớp sẵn có của C#, và giao diện của RemoveAll và ConvertAll như sau :

public int RemoveAll(Predicate<T> match);
public delegate bool Predicate<T>(T obj);

public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter);
public delegate TOutput Converter<TInput, TOutput>(TInput input);

Và sau đây là ví dụ đoạn code sử dụng chúng, cho thấy cách sử dụng delegate, ví dụ sau cho thấy là ta có thể truyền một function như là tham số của function khác.

public class Test{
public void testListAndDelegate()
{
List<int> listNo = new List<int> (new int[]{1, 2, 3, 3, 4, 5, 6, 5, 3});

// thuc hien xoa cac element co gia tri 3 trong listNo
// trong do equalThree la mot function dc khai bao ben duoi
listNo.RemoveAll(equalThree);

// thuc hien chuyen listNo thanh mot danh sach List tuong ung
// trong do Convert.ToString la mot function cua C# co
// khai bao "public static string ToString(int no)"

List<string> listStr = listNo.ConvertAll<int, string>(Convert.ToString);
}
private bool equalThree(int no)
{
return (no == 3);
}
}

- Tìm kiếm sử dụng Delegate thay vì sử dụng IComparer :
Đây lại là một ví dụ sử dụng Template Delegate, dc dùng trong hàm LinearSearch, hàm này viết dưới dạng Template, nên có thể thích ứng với rất nhiều input khác nhau

public class CommonFunction{
// ham nay tra ve vi tri cua phan tu thuoc array of type tuong ung voi key of type
// trong do E va K la hai kieu bat ki
// Compare la delegate da dc khai bao ben tren
public static int linearSearch<E, K>(List list, K key, Compare<E, K> compare)
{
for (int i = 0; i < list.Count; i++) {
if (compare(list[i], key) == 0) {
return i;
}
}
return CommonConstant.UNFOUND;
}
}// end of CommonFunction
/////////////

public struct Pair{
public int no;
public string name;
public Pair(int inNo, string inName){
no = inNo;
name = inName;
}
}

public class Test{

// khai nay dc khai bao de su dung nhu la tham so
// cho ham linearSearch ben duoi
private int compareFunc (Pair x, int y)
{
return x.no.CompareTo(y);
}

public void testLinearSearch()
{
List<Pair> list = new List<Pair>();
list.Add(new Pair(1, "Mot"));
list.Add(new Pair(3, "Ba"));
list.Add(new Pair(4, "Bon"));
list.Add(new Pair(2, "Hai"));

// tiep theo, ta muon tim index cua phan tu tuong ung voi "no" = 3,
// ta chi can code nhu sau, compareFunc chinh la ham ben tren
int index = CommonFunction.linearSearch(list, 3, compareFunc);
}

}// end of Test

Thứ Bảy, 29 tháng 11, 2008

Đoạn mã chống copy bài viết và hình ảnh

<script language="JavaScript1.2">
var message="Text Here";
function click(e) {
if (document.all) {
if (event.button==2||event.button==3) {
alert(message);
return false;
}
} else {
if (e.button==2||e.button==4) {
e.preventDefault();
e.stopPropagation();
alert(message);
return false;
}
}
}
if (document.all) { // for IE
document.onmousedown=click;
} else { // for FF
document.onclick=click;
}
</script>

<script type="text/javascript">
function ehan( evnt )
{
if( evnt.which == 3 )
{
alert( "Text Here" );
return false;
}
return true;
}
function ocmh()
{
alert( "Text Here" );
return false;
}
document.oncontextmenu = ocmh;
document.captureEvents( Event.MOUSEDOWN );
if( document.layers ) document.onmousedown = ehan;
</script>

<script language="JavaScript">
if (window!=top){top.location.href=location.href;}
</script>

<script type="text/javascript">
<!--
var omitformtags=["input", "textarea", "select"]
omitformtags=omitformtags.join("|")
function disableselect(e){
if (omitformtags.indexOf(e.target.tagName.toLowerCase())==-1)
return false
}
function reEnable(){
return true
}
if (typeof document.onselectstart!="undefined")
document.onselectstart=new Function ("return false")
else{
document.onmousedown=disableselect
document.onmouseup=reEnable
}
-->
</script>

<script language="JavaScript">
if (window!=top){top.location.href=location.href;}
</script>

<script type="text/javascript">
<!--
var omitformtags=["input", "textarea", "select"]
omitformtags=omitformtags.join("|")
function disableselect(e){
if (omitformtags.indexOf(e.target.tagName.toLowerCase())==-1)
return false
}
function reEnable(){
return true
}
if (typeof document.onselectstart!="undefined")
document.onselectstart=new Function ("return false")
else{
document.onmousedown=disableselect
document.onmouseup=reEnable
}
-->
</script>

Đặc điểm của một số thuộc tính CSS - Sự khác nhau của IE và chuẩn chung

Các vấn đề sẽ đề cập
1. IE and the box model
2. IE versions and Doctype modes

IE and the box model

Cho dù bạn có thích hoặc căm ghét, Internet Explorer của Microsoft vẫn là một trình duyệt chính đựơc sử dụng hiện nay. Điều đó có nghĩa là vài điểm bạn cần xem xét khi thiết kế để khắc phục một vài điểm chưa hợp lý về CSS.
Một ví dụ dơn giản là một số phiên bản của IE thể hiện các hộp (box model) một cách khác biệt so với các trình duyệt chuẩn. Và các file CSS của bạn nhìn trên IE sẽ khác so với các trình duyệt còn lại như: firefox, opera.
Với một hộp vuông có chiều rộng 200px và được bạn gán thuộc tính "padding:20px; border:20px;" thì chiều rộng chuẩn của nó sẽ được tính như sau
Chiều rộng thể hiện
chiều rộng chuẩn (200px) + padding (20px+20px) + borders (20px+20px) = 280px.
Thế nhưng một vài phiên bản của IE sẽ tính ra chiều rộng bằng công thức: content, padding and borders together = 200px.
Nguồn:http://css.maxdesign.com.au/listamatic/about-boxmodel.htm

Chủ Nhật, 23 tháng 11, 2008

Sử dụng Connection Strings với CSDL SQL Server 2005

SQL Native Client ODBC Driver:

Standard security:
Driver={SQL Native Client};Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;

Trusted Connection:
Driver={SQL Native Client};Server=myServerAddress;Database=myDataBase;Trusted_Connection=yes;

Ghi chú: "Integrated Security=SSPI" tương tự như "Trusted_Connection=yes"

Connecting to an SQL Server instance:
Driver={SQL Native Client};Server=myServerName\theInstanceName;Database=myDataBase;Trusted_Connection=yes;

Prompt for username and password:

oConn.Properties("Prompt") = adPromptAlways
Driver={SQL Native Client};Server=myServerAddress;Database=myDataBase;
Enabling MARS (multiple active result sets):
Driver={SQL Native Client};Server=myServerAddress;Database=myDataBase;Trusted_Connection=yes;MARS_Connection=yes;

Ghi chú:

"MultipleActiveResultSets=true" tương tự như "MARS_Connection=yes"

Sử dụng ADO.NET 2.0 cho MARS. MARS không hỗ trợ ADO.NET 1.0 và ADO.NET 1.1.

Encrypt data sent over network:
Driver={SQL Native Client};Server=myServerAddress;Database=myDataBase;Trusted_Connection=yes;Encrypt=yes;

Attach a database file on connect to a local SQL Server Express instance:
Driver={SQL Native Client};Server=.\SQLExpress;AttachDbFilename=c:\asd\qwe\mydbfile.mdf; Database=dbname;Trusted_Connection=Yes;

Attach a database file, located in the data directory, on connect to a local SQL Server Express instance:
Driver={SQL Native Client};Server=.\SQLExpress;AttachDbFilename=|DataDirectory|mydbfile.mdf; Database=dbname;Trusted_Connection=Yes;

Database mirroring:
Data Source=myServerAddress;Failover Partner=myMirrorServer;Initial Catalog=myDataBase;Integrated Security=True;

SQL Native Client OLE DB Provider:

Standard security:
Provider=SQLNCLI;Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;

Trusted connection:
Provider=SQLNCLI;Server=myServerAddress;Database=myDataBase;Trusted_Connection=yes;

Connecting to an SQL Server instance:
Provider=SQLNCLI;Server=myServerName\theInstanceName;Database=myDataBase;Trusted_Connection=yes;

Prompt for username and password:
oConn.Properties("Prompt") = adPromptAlways
oConn.Open "Provider=SQLNCLI;Server=myServerAddress;DataBase=myDataBase;

Enabling MARS (multiple active result sets):
Provider=SQLNCLI;Server=myServerAddress;Database=myDataBase;Trusted_Connection=yes;MarsConn=yes;

Ghi chú:

"MultipleActiveResultSets=true" tương tự như "MARS_Connection=yes"

Sử dụng ADO.NET 2.0 cho MARS. MARS không hỗ trợ ADO.NET 1.0 và ADO.NET 1.1.

Encrypt data sent over network:
Provider=SQLNCLI;Server=myServerAddress;Database=myDataBase;Trusted_Connection=yes;Encrypt=yes;

Attach a database file on connect to a local SQL Server Express instance:
Provider=SQLNCLI;Server=.\SQLExpress;AttachDbFilename=c:\asd\qwe\mydbfile.mdf; Database=dbname;Trusted_Connection=Yes;

Attach a database file, located in the data directory, on connect to a local SQL Server Express instance:
Provider=SQLNCLI;Server=.\SQLExpress;AttachDbFilename=|DataDirectory|mydbfile.mdf; Database=dbname;Trusted_Connection=Yes;

Database mirroring:
Data Source=myServerAddress;Failover Partner=myMirrorServer;Initial Catalog=myDataBase;Integrated Security=True;

SqlConnection (.NET):

Standard Security:
Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;

hoặc:

Server=myServerAddress;Database=myDataBase;User ID=myUsername;Password=myPassword;Trusted_Connection=False;

Trusted Connection:
Data Source=myServerAddress;Initial Catalog=myDataBase;Integrated Security=SSPI;

hoặc:

Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;

Connecting to an SQL Server instance:
Server=myServerName\theInstanceName;Database=myDataBase;Trusted_Connection=True;

Trusted Connection from a CE device:
Data Source=myServerAddress;Initial Catalog=myDataBase;Integrated Security=SSPI;User ID=myDomain\myUsername;Password=myPassword;

Connect via an IP address:
Data Source=190.190.200.100,1433;Network Library=DBMSSOCN;Initial Catalog=myDataBase;User ID=myUsername;Password=myPassword;

Ghi chú: 1433 là cổng mặc định của SQL Server.

Enabling MARS (multiple active result sets):
Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;MultipleActiveResultSets=true;

Ghi chú:

"MultipleActiveResultSets=true" tương tự như "MARS_Connection=yes"

Sử dụng ADO.NET 2.0 cho MARS. MARS không hỗ trợ ADO.NET 1.0 và ADO.NET 1.1.

Attach a database file on connect to a local SQL Server Express instance:
Server=.\SQLExpress;AttachDbFilename=c:\asd\qwe\mydbfile.mdf;Database=dbname;Trusted_Connection=Yes;

Attach a database file, located in the data directory, on connect to a local SQL Server Express instance:
Server=.\SQLExpress;AttachDbFilename=|DataDirectory|mydbfile.mdf; Database=dbname;Trusted_Connection=Yes;

Using an User Instance on a local SQL Server Express instance:
Data Source=.\SQLExpress;Integrated Security=true;AttachDbFilename=|DataDirectory|\mydb.mdf;User Instance=true;

Database mirroring:
Data Source=myServerAddress;Failover Partner=myMirrorServer;Initial Catalog=myDataBase;Integrated Security=True;

Asynchronous processing:
erver=myServerAddress;Database=myDataBase;Integrated Security=True;Asynchronous Processing=True;

SQL Server 2005 special:
C#
using(SqlConnection connection = new SqlConnection("context connection=true"))
{
connection.Open();
// Use the connection
}

VB.Net
Using connection as new SqlConnection("context connection=true")
connection.Open()
' Use the connection
End Using

Link tham khảo

Thứ Hai, 17 tháng 11, 2008

Tìm kiếm trong lập trình

Để đọc hiểu bài này, bạn phải đọc 2 bài trước nó gồm :
- Lập trình Generic với C#.
- Sắp xếp.

Bên cạnh thao tác sắp xếp, ta cũng có một số thao tác cũng rất hay gặp khi lập trình liên quan đến tìm kiếm, ví dụ :
- Tìm kiếm một phần tử trong một danh sách chưa sắp xếp.
- Tìm kiếm một phần tử trong một danh sách đã dc sắp xếp rồi (giải thuật phổ biến nhất là BinarySearch).
- Insert một phần tử vào một danh sách đang dc sắp xếp rồi mà vẫn đảm bảo tính sắp xếp của danh sách đó (thường dùng BinarySearch để xác định ví trí để insert trc, rồi mới insert).
- Xác định vị trí cần thiết trong một danh sách đã sắp xếp để insert một phần tử mới vào (cũng dùng BinarySearch).

Bài viết này tôi sẽ giới thiệu một số hàm dc viết theo kiểu Generic Function, với tính tái sử dụng rất cao, performance tốt, có thể được sử dụng trong nhiều dự án C# khác nhau. Trừ khi yêu cầu của bạn rất đặc thù, còn không thì >95%, bạn có thể sử dụng nó mỗi khi gặp những vấn để nói trên. Trong bài viết này, tôi sẽ gửi kèm theo file.cs này, vì có rất nhiều thủ tục, bạn có thể sử dụng nó như là thư viện cho dự án của mình. Một số trường hợp còn thiếu (ex : tìm kiếm sử dụng IComparer), bạn có thể bổ sung, bằng cách viết tương tự, rất đơn giản.
Đầu tiên, thì cũng như thao tác Sort, BinarySearch cũng đã dc .Net cung cấp sẵn, tuy nhiên rất tiếc là nó có một hạn chế rất lớn, và tớ hầu như ko sử dụng hàm đó của .Net, và tự viết lấy theo Generic Function.
Nhược điểm của BinarySearch của .Net.
Giao diện hàm đó như sau (xem phần definition của List hoặc Array) :

public class List<T>{
int BinarySearch(T item);
}

Giả sử bạn có một danh sách Person{int id, string name}. Nếu bạn muốn tìm tên của người có id = 10 thì sao. Với hàm BS này, bạn phải truyền vào một đối tượng Person có id=10, và name=null(cái ji cũng dc :D, vì thao tác so sánh thực hiện trên id) => performance ko tốt do phải new Person.

Vậy nếu tôi chỉ muốn truyền vào id thôi, ko new một Person nữa có dc ko? OK với những hàm được giới thiệu sau đây.
Nếu danh sách Person là một List thì như sau :

public static int searchOnSorted<E, K>(IList<E> list, K key) where E : IComparable<K>
{
if (list == null) return CommonConstant.UNFOUND;

int mid = 0,
head = 0,
tail = list.Count - 1;
while (head <= tail) {
mid = (head + tail) >> 1;
int cmp = list[mid].CompareTo(key);
if (cmp > 0) {
tail = mid - 1;
} else if (cmp < 0) {
head = mid + 1;
} else {
return mid;
}
}
return CommonConstant.UNFOUND;
} // end of BinarySearch

Nếu danh sách Person là một Person[] thì như sau :

public static int searchOnSorted<E, K>(E[] array, K key) where E : IComparable<K>
{
if (array == null) return CommonConstant.UNFOUND;

int mid = 0,
head = 0,
tail = array.Length - 1;
while (head <= tail) {
mid = (head + tail) >> 1;
int cmp = array[mid].CompareTo(key);
if (cmp > 0) {
tail = mid - 1;
} else if (cmp < 0) {
head = mid + 1;
} else {
return mid;
}
}
return CommonConstant.UNFOUND;
} // end of BinarySearch

Để có thể sử dụng dc hàm này, bạn cần chỉnh lớp Person một chút như sau, bắt nó implement IComparable như sau :

public class Person : IComparable<Person>, IComparable<int>
{
public int id;
public string name;
public Person(int inNo, string inName)
{
id = inNo;
name = inName;
}

#region IComparable Members
public int CompareTo(Person other)

Chủ Nhật, 16 tháng 11, 2008

Sắp xếp

Sắp xếp là một thao tác rất thường gặp khi lập trình, rất may, trong C#, Java, C++ ... đã cung cấp sẵn những hàm phục vụ vấn đề này, biết sử dụng thư viện này sẽ tiết kiệm dc kha khá thời gian lập trình, code lại trong sáng, dễ đọc. Bài viết này sẽ giới thiệu về cách thực hiện sắp xếp trong C#. Trừ khi yêu cầu quá đặc biệt, thì nhìn chung >95% các trường hợp, bạn ko cần phải tự viết các hàm sắp xếp cho dự án của mình.
1. Sắp xếp một danh sách hoặc mảng các đối tượng
Giả sử ta có đối tượng Person{int id; string name}. Ta muốn sau này có nhu cầu sắp xếp một danh sách/mảng các Person (List, IList hoặc Person[] và ...) tăng dần theo id, thì ta phải cho lớp Person này implement IComparable như sau :

public class Person : IComparable<Person>
{
public int id;
public string name;
public Person(int inNo, string inName)
{
id = inNo;
name = inName;
}

#region IComparable Members
///
/// Ham nay se duoc su dung khi goi ham sap xep cung cap boi .Net.
/// Ngam dinh la sap xep tang dan, neu ham nay tra lai ket qua nhu sau :
/// == 1 : this > other;
/// == 0 : this == other;
/// == -1 : this <>
/// Neu co tinh muon sap xep giam dan thoi thi co the viet nhu sau :
/// return -id.CompareTo(other.id);
///
///
///
public int CompareTo(Person other)
{
return id.CompareTo(other.id);
}
#endregion
}


Sau khi có lớp Person như trên, ta thực hiện sắp xếp như sau :
Với List, IList thì

List<Person> personList = new List<Person>();
// add them mot so doi tuong Person vao bien list noi tren
// code here

//////////////////////////////////////////////////////////////////////////
// thuc hien sap xep danh sach Person tang dan theo id cua Person
// ham Sort nay da duoc .Net cung cap san, dung QuichSort, co giao dien :
// public void Sort();
// ham Sort nay se tu dong su dung ham "public int CompareTo(Person other)"
// de thuc hien sap xep.
personList.Sort();
// done, danh sach da sap xep xong, tang dan theo id.


Với Array

//////////////////////////////////////////////////////////////////////////
Person[] personArr = new Person[5];
// add them mot so doi tuong Person vao bien array noi tren
// code here

//////////////////////////////////////////////////////////////////////////
// thuc hien sap xep mang Person tang dan theo id cua Person
// ham Sort nay da duoc .Net cung cap san, dung QuichSort, co giao dien :
// public void Sort();
// ham Sort nay se tu dong su dung ham "public int CompareTo(Person other)"
// de thuc hien sap xep.
Array.Sort(personArr);
// done, mang da sap xep xong, tang dan theo id.

Nếu muốn sắp xếp giảm dần thì như thế nào ?
Có 2 cách :
- Cách 1 : bạn sửa hàm CompareTo của Person (chỉ khi ta chỉ muốn sắp xếp giảm dần thôi), làm như thế nào thì mình đã comment trong hàm CompareTo bên trên rồi.
- Cách 2 : bạn thực hiện reverse lại, làm như sau

//////////////////////////////////////////////////////////////////////////
// neu muon lay danh sach giam dan, ta co the thuc hien theo 2 buoc
// thuc hien sap xep tang dan theo cach noi tren
personList.Sort(); // => de sap xep tang dan.
personList.Reverse(); // => de dao nguoc thu tu sap xep
// done, ta da co danh sach dc sap xep giam dan

Vậy lúc này bạn đã có thể sắp xếp theo id rồi, nhưng lúc khác bạn lại muốn có một danh sách sắp xếp theo name thì sao ?
Lúc này, bạn định nghĩa thêm một lớp để implement IComparer, lớp đó như sau :

public class PersonComparerIncreaseOnName: IComparer<Person>
{
#region IComparer Members
///
/// Ham nay se duoc su dung khi thuc hien sap xep tang dan Person theo name.
///
///
///
///
public int Compare(Person x, Person y)
{
return x.name.CompareTo(y.name);
}
#endregion
}


Và khi muốn gọi sắp xếp, ta gọi hàm sau :
Với List, IList thì

//////////////////////////////////////////////////////////////////////////
// thuc hien sap xep danh sach Person tang dan theo name cua Parson
// ham Sort nay da duoc .Net cung cap san, dung QuickSort, co giao dien :
// public void Sort(IComparer);
// ham Sort nay se tu dong su dung ham "public int Compare(Person x, Person y)"
// de thuc hien sap xep.
personList.Sort(new PersonComparerIncreaseOnName());
// done, danh sacg da sao xeo tang dan theo name.


Với Array thì

//////////////////////////////////////////////////////////////////////////
// thuc hien sap xep mang Person tang dan theo name cua Parson
// ham Sort nay da duoc .Net cung cap san, dung QuickSort, co giao dien :
// public void Sort(IComparer);
// ham Sort nay se tu dong su dung ham "public int Compare(Person x, Person y)"
// de thuc hien sap xep.
Array.Sort(personArr, new PersonComparerIncreaseOnName());
// done, mang da sap xep xong tang dan theo name.


Nếu tôi sử dụng một lớp có sẵn, tôi không thể khiến lớp đó implement IComparable thì sao ?
Ko vấn đề ji, bạn làm y hệt theo cách ta sắp xếp theo name, định nghĩa thêm một class implement IComparer như trên, và ta có thể sắp xếp như thường.

2. Sắp xếp một danh sách hoặc một mảng các Struct
Hoàn toàn ko có khác biệt gì với sắp xếp struct và class, vì trong C#, một struct cũng có thể implement các Interface giống hệt class, ví dụ sau là struct Person :

public struct Person : IComparable<Person>
{
public int id;
public string name;
public Person(int inNo, string inName)
{
id = inNo;
name = inName;
}

#region IComparable Members
///
/// Ham nay se duoc su dung khi goi ham sap xep cung cap boi .Net.
/// Ngam dinh la sap xep tang dan, neu ham nay tra lai ket qua nhu sau :
/// == 1 : this > other;
/// == 0 : this == other;
/// == -1 : this <>
/// Neu co tinh muon sap xep giam dan thoi thi co the viet nhu sau :
/// return -id.CompareTo(other.id);
///
///
///
public int CompareTo(Person other)
{
return id.CompareTo(other.id);
}
#endregion
}

Đối với sắp xếp trong Java hay C++ cũng có kỹ thuật tương tự.
That's all. Go Together In Development.

Thứ Sáu, 14 tháng 11, 2008

Make run a Java program with command

// class NewClass => file NewClass.java
package test;

public class NewClass {
int i;
public NewClass(int index) {
// TODO Auto-generated constructor stub
i = index;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}

// class Test contains main function => file Test.java
package test;

public class Test {
public static void main(String[] args)
{
NewClass newClass = new NewClass(10);
System.out.println(newClass.getI());
}

}

Lâu rồi ko viết Java, trước có note lại cách make run để ghi nhớ. Ghi nhớ này chưa hoàn chỉnh và hệ thống lắm nhưng giờ chưa có điều kiện để viết, lúc nào rảnh thì viết sau. Để make run một Java program, ta dùng lệnh sau :
/* command to execute the program, with file.class (not yet jar)
* . : current directory.
* test.Test : test is package name, and Test is the main Class (do not go into the test directory).
*/

java -classpath . test.Test

Chủ Nhật, 9 tháng 11, 2008

Lập trình generic (template) với C#

Trong C# hỗ trợ lập trình generic khá mạnh, nếu bạn biết sử dụng lập trình generic thì bạn tiết kiệm được khá khá thời gian lập trình, và tính tái sử dụng code rất cao, vẫn đảm bảo tính trong sáng khi code mà performance của chương trình hầu như ko giảm. Trong C#, bạn có thể lập trình Generic với Class, Struct, Function.
1. Lập trình Generic với Class.
Chắc bạn đã quá quen thuộc với khai báo
List nameList = new List();
Đây là khai báo sử dụng một danh sách các string, trong đó lớp List là một lớp được lập trình dạng generic, bạn có thể dễ dàng khai báo một danh sách các đối tượng thuộc kiểu bất kì. Rõ ràng tính tái sử dụng lớp List cao hơn rất nhiều lớp List ko có generic.
Áp dụng phương pháp cách định nghĩa lớp này, chúng ta có thể tạo những lớp generic khác nhau. Tớ ví dụ ở đây lớp Couple được sử dụng rất nhiều khi tớ viết code.

    public class Couple<T, E>
{
public T elementA;
public E elementB;
public Couple(T inA, E inB)
{
elementA = inA;
elementB = inB;
}
}

Lớp này được dùng khi bạn muốn có một đối tượng tạm thời chỉ gồm hai phần tử, bình thường bạn phải định nghĩa một class mới để phù hợp với kiểu của 2 phần tử nói trên, nhưng với Couple bạn ko cần thiết phải làm điều đó.
Ví dụ bạn muốn một đối tượng gồm 2 phần tử string và một số integer, bạn khai báo như sau :
Couple couple = new Couple("Age", 29);
Khi đó couple.elementA sẽ có kiểu string nhận giá trị "Age" và couple.elementB sẽ có kiểu int nhận giá trị 29.
Cũng với lớp này, bạn có thể tạo một lớp danh sách các bộ đôi string và int như sau :

List<Couple<string, int>> listCouple = new List<Couple<string, int>> ();

Và khi đó List[5].elementA sẽ có kiểu string, trả về giá trị string của Couple có index 5 trong List nói trên.
Hoặc khi hàm bạn viết cần phải trả về 2 đối tượng, thì việc sử dụng Couple cũng là một cách tốt, trong sáng và vẫn rất OPP:D.
Chú ý, bạn có thể bổ sung thêm Property cho lớp Couple nếu thấy cần thiết (khi lập trình aspx chẳng hạn), thêm như bình thường.

    public class Couple<T, E>
{
public T elementA;
public E elementB;
public Couple(T inA, E inB)
{
elementA = inA;
elementB = inB;
}
public T ElementA
{
get{return elementA;}
set{elementA = value;}
}
}

Tương tự như vậy, bạn có thể khai báo thêm các lớp Generic Triple (bộ ba) và Quad

    public class Triple<T, E, F>
{
public T elementA;
public E elementB;
public F elementC;
public Triple(T inA, E inB, F inC)
{
elementA = inA;
elementB = inB;
elementC = inC;
}
}

public class Quad<T, E, F, G>
{
public T elementA;
public E elementB;
public F elementC;
public G elementD;
public Quad(T inA, E inB, F inC, G inD)
{
elementA = inA;
elementB = inB;
elementC = inC;
elementD = inD;
}
}

Bạn có thể tận dụng 3 lớp nói trên trong các dự án C# của bạn, sẽ tiết kiệm nhiều thời gian đấy. Chú ý phải định nghĩa thêm nhé, đây không phải là lớp sẵn có của .Net.

2. Lập trình Generic với Struct.
Nhìn chung, ko có ji khác biệt trong cách lập trình Generic Struct và Generic Class, ví dụ sau là Struct Couple:

    public struct Couple<T, E>
{
public T elementA;
public E elementB;
public Couple(T inA, E inB)
{
elementA = inA;
elementB = inB;
}
public T ElementA
{
get{return elementA;}
set{elementA = value;}
}
}

Nói chung, nếu ko phải quá bận tâm vào performance, thì hầu như ta có thể dùng Class thay vì dùng Struct trong lập trình C#. Tớ sẽ phân biệt sự khác nhau, và ưu nhược điểm của việc sử dụng Struct trong C# trong một bài viết khác.

3. Lập trình Generic Function.
C# cũng cho phép lập trình Generic với hàm, sau đây là một ví dụ :

    public string toString<T>(List<Couple<string, T>> list)
{
string result = "";
foreach (Couple<string, T> pair in list){
string tmp = pair.elementA + " : " + pair.elementB.ToString();
result += tmp + '\n';
}
return result;
}

Đây là ví dụ một hàm trả về một string tương ứng với nội dung của một danh sách bộ đôi của một String và một loại object nào đó (string, int, ...) sẽ được thay thể trong mỗi trường hợp call cụ thể. Có lẽ đây ko phải là ví dụ hay cho Generic Function. Nhưng nhờ lập trình Generic Function, tớ đã có thể viết hàm BinarySearch rất tổng quát, có thể được tái sử dụng trong rất nhiều dự án khác, tiết kiệm rất nhiều thời gian. Tớ sẽ giới thiệu hàm này trong bài nói về Sắp xếp và Tìm kiếm sau.