2011年3月23日 星期三

關於字串處理

有一段URLhttp://www.blogger.com/index.htm

l請取出index.html這段字串。

做了一些測驗,測驗的程式碼如下:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
applicationComplete="application1_applicationCompleteHandler(event)"
>
<fx:Script>
<![CDATA[
import mx.core.UIComponent;
import mx.events.FlexEvent;
import spark.skins.spark.mediaClasses.fullScreen.FullScreenButtonSkin;
/**----------------------------------------
這段是測試程式碼用的程式碼 區塊
------------------------------------------*/
private var _reportCollection:Vector.<Object> = new Vector.<Object>;
protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
 //替BTN加偵聽式
 addTargetListener(this.startBtn , startBtn_mouseDownHandler)
 //用來驗證輸出是否正解
 //reportBoard_TA.text = examA1();
 //reportBoard_TA.text = examA2();
 //reportBoard_TA.text = examA3();
 //reportBoard_TA.text = examA4();
}


private function addTargetListener(obj:IEventDispatcher , method:Function):void
{
 if(obj)
   obj.addEventListener(MouseEvent.MOUSE_DOWN , method);
}


protected function startBtn_mouseDownHandler(event:MouseEvent):void
{
 if(reportBoard_TA.text.length > 0)
  reportBoard_TA.text = "";
 //參數要輸入,要執行的funciton
 //startExecuteTestFunction(examA1);
 //startExecuteTestFunction(examA2);
 startExecuteTestFunction(examA3);
 //startExecuteTestFunction(examA4);
}

//執行10次,100000次的Method測試
public function startExecuteTestFunction(byExcuteMethod:Function , loopCount:int=10):void
{
 var reportCount:int = 0;
 for( reportCount ; reportCount < loopCount ; reportCount ++)
 {
  _reportCollection[reportCount] = executeFunction(byExcuteMethod);
  report_Time(reportBoard_TA,_reportCollection[reportCount]);
 }
 report_AVG_Time(reportBoard_TA , outAVG(_reportCollection));
}


//對要測試的Method執行100000圈的測試
private function executeFunction(method:Function , loopCount:int=100000):Object
{
 var _beforTime:Number=0;
 var _afterTime:Number=0;
 var _executeTime:Number;
 var _currentCount:int = 0;


 _beforTime = getTimer();
 for( _currentCount ; _currentCount < loopCount ; _currentCount++)
 {
  method();
 }
 _afterTime = getTimer();


 _executeTime = (_afterTime - _beforTime);
 return makeValueObject(_executeTime , loopCount);
}
//製造一個職物件
private function makeValueObject(executeTime:Number , loopCount:int):Object
{
 return {time:executeTime , count:loopCount};
}


//計算平均值
private function outAVG(ar:Vector.<Object>):Number
{
 if(_reportCollection != null && _reportCollection.length > 0)
 {
  var i:int = 0;
  var total:Number=0;
  for( i ; i < ar.length ; i++)
  {
   total += ar[i].time;
  }
  return total / ar.length;
 }
 return -1;
}




//
protected function report_Time(target:TextArea , valueObj:Object):void
{
 target.text += "運算圈數:" + valueObj.count + '\n';
 target.text += "運算時間:" + valueObj.time + "毫秒" + '\n';
 target.text += "---------------------------------" + '\n';
}


protected function report_AVG_Time(target:TextArea , avgTime:Number):void
{
 target.text += "平均時間:" + avgTime + "毫秒" + '\n';
 target.text += "---------------------------------" + '\n';
}


/**-----------------------------------------------------------
三個題目如下
第一題:http://www.facebook.com/index.html 請取出index.html
第二題:[1,5,6,7,'a','b',5,'ef'] ,請將字串與整數分成兩各陣列存放
第三題:這題要算出三月工作天總數
限制條件,使用ActrionScript3.0 語言解題
--------------------------------------------------------------*/
//-----------------------
//大家熱心提供的解題方式
//-----------------------

//第一題
private var str:String = "http://www.test.yes/index.html";


/**Algren Tsai*/
private function examA1():String
{
 var count:int = str.length-1;
 var targetIndex:int=-1;
 for(count ; count >= 0 ; count--)
 {
  if (str.charAt(count) == "/" ){ 
  targetIndex = count + 1;
  break;
 }
}


 if(targetIndex >= 0 ){
  return(str.slice( targetIndex , str.length));
 }else{
  return null;
 }
}


/**Noah Lue*/
private function examA2():String
{
 return(str.split("/")[str.split("/").length-1]);
 //index.html
}


/**Intestine*/
private function examA3():String
{
 return str.substring(str.lastIndexOf("/")+1,str.length);
}


private function examA4():String
{
 var targetIndex:int;
 targetIndex = str.lastIndexOf("/") + 1;
 if(targetIndex >= 0 ){
  return(str.slice( targetIndex , str.length));
  }else{
  return null;
  }
}


]]>
</fx:Script>
 <s:HGroup>
  <s:Panel title="B看板" width="300" height="520"&gt;
   <s:TextArea id="reportBoard_TA" editable="false" width="100%" height="100%"/>
  </s:Panel>
  <s:Button id="startBtn" label="測驗開始" />
 </s:HGroup>
</s:Application&gt;


輸出結果
這是我的第一題解法,我的想法是從後面往回取得第一個/的index在取回index.html。
因為對於String,API不夠熟悉所以自己跑loop取/的index。/**Algren Tsai*/
private var str:String = "http://www.test.yes/index.html";
private function examA1():String
{
 var count:int = str.length-1;
 var targetIndex:int=-1;
 for(count ; count >= 0 ; count--)
 {
  if (str.charAt(count) == "/" ){
   targetIndex = count + 1;
   break;
  }
 }
 if(targetIndex >= 0 ){
  return(str.slice( targetIndex , str.length));
 }else {
  return null;
 }
}

運算圈數:100000
運算時間:312毫秒
---------------------------------
運算圈數:100000
運算時間:312毫秒
---------------------------------
運算圈數:100000
運算時間:328毫秒
---------------------------------
運算圈數:100000
運算時間:312毫秒
---------------------------------
運算圈數:100000
運算時間:312毫秒
---------------------------------
運算圈數:100000
運算時間:312毫秒
---------------------------------
運算圈數:100000
運算時間:327毫秒
---------------------------------
運算圈數:100000
運算時間:297毫秒
---------------------------------
運算圈數:100000
運算時間:327毫秒
---------------------------------
運算圈數:100000
運算時間:312毫秒
---------------------------------
平均時間:315.1毫秒

我們可以看到輸出是315.1ms

而Intestine所提供的方式,是都是用了AS3,String本身的API(),從結果我們會看到快很多
/**Intestine*/
private function examA3():String
{
 return str.substring(str.lastIndexOf("/")+1,str.length);
}

輸出
 
運算圈數:100000
運算時間:110毫秒
---------------------------------
運算圈數:100000
運算時間:90毫秒
---------------------------------
運算圈數:100000
運算時間:80毫秒
---------------------------------
運算圈數:100000
運算時間:90毫秒
---------------------------------
運算圈數:100000
運算時間:100毫秒
---------------------------------
運算圈數:100000
運算時間:90毫秒
---------------------------------
運算圈數:100000
運算時間:80毫秒
---------------------------------
運算圈數:100000
運算時間:90毫秒
---------------------------------
運算圈數:100000
運算時間:90毫秒
---------------------------------
運算圈數:100000
運算時間:90毫秒
---------------------------------
平均時間:91毫秒
---------------------------------

真的是非常快速

因此我將examA1()改良成examA4()做測試
private function examA4():String
{
 var targetIndex:int;
 targetIndex = str.lastIndexOf("/") + 1;
 if(targetIndex >= 0 ) {
 return(str.slice( targetIndex , str.length));
 }else {
  return null;
 }
}

輸出
運算圈數:100000
運算時間:120毫秒
---------------------------------
運算圈數:100000
運算時間:100毫秒
---------------------------------
運算圈數:100000
運算時間:90毫秒
---------------------------------
運算圈數:100000
運算時間:100毫秒
---------------------------------
運算圈數:100000
運算時間:90毫秒
---------------------------------
運算圈數:100000
運算時間:100毫秒
---------------------------------
運算圈數:100000
運算時間:100毫秒
---------------------------------
運算圈數:100000
運算時間:100毫秒
---------------------------------
運算圈數:100000
運算時間:100毫秒
---------------------------------
運算圈數:100000
運算時間:90毫秒
---------------------------------
平均時間:99毫秒
---------------------------------

請看下列比較
  • examA1:平均時間:315.1毫秒
  • examA2:平均時間:99毫秒

這告訴我們一件事,top level裡,他的內部API是設計AS3的語言工具所寫的,因此比起AS3本身是少了一層,況且內部運作設計已經優化。

所以使用top level的東西如int,String,Number,Array........等等等的,若有內部API則用之,不要自己寫演算,除非內部API並無你要的演算方式。

但是其實雖然看其來差很多的毫秒,其實是因為執行了100K圈的結果,真正呼叫一次速度根本沒有感覺,所以其實這裡只是一種觀念,讓你知道一下速度有差異重要的是寫碼風格要易讀,邏輯要清楚。


讓我們來看看Noah大的方式
/**Noah Lue*/
private function examA2():String
{
 return(str.split("/")[str.split("/").length-1]);
 //index.html
}

運算圈數:100000
運算時間:470毫秒
---------------------------------
運算圈數:100000
運算時間:480毫秒
---------------------------------
運算圈數:100000
運算時間:470毫秒
---------------------------------
運算圈數:100000
運算時間:470毫秒
---------------------------------
運算圈數:100000
運算時間:470毫秒
---------------------------------
運算圈數:100000
運算時間:480毫秒
---------------------------------
運算圈數:100000
運算時間:470毫秒
---------------------------------
運算圈數:100000
運算時間:460毫秒
---------------------------------
運算圈數:100000
運算時間:480毫秒
---------------------------------
運算圈數:100000
運算時間:460毫秒
---------------------------------
平均時間:471毫秒
---------------------------------

雖然都是利用內部API(),但是反而比examA1()慢了,這可能是因為某些API算法並不是第一題的最佳演算法才會如此。

至於寫碼風格易讀,就要看是在什麼環境下,如果是Server-Side就要追求極致效能,那麼就會犧牲掉部分的易讀性換取效能,若是遊戲開發也有可能會如此。

如果可以使用正則運算來做或許會更好!

沒有留言:

張貼留言