假設我在View上有一個@helper可以長出我需要的樣式,傳入的變數意義如下-options
: 一個項目的選項集合(包含選項名稱Name
與選項值Value
)checkResult
: 一個項目的選擇結果集合(多選,只存值Value
)
透過以下@helper將每一個選項options
印出,然後依據選擇結果checkResult
決定是否要添加屬性"checked='checked'"
但使用Array.IndexOf
會造成效率過慢,希望可以透過縮減迴圈的方法,讓效率好一些,目前做法是,當已經比對過那些值,接下來在跑迴圈的時候,就不用比對剛剛比對過的值,以達到減少跑迴圈的次數,不知道是否有其他更好的方式呢?還請各位幫忙,謝謝!
@helper GetTestItemResult(dynamic[] options, dynamic checkResult) {
for(var i = 0; i<options.Length; ++i) {
var option = options[i];
<input type='checkbox'
@Html.Raw((Array.IndexOf(checkResult.Option, option.Value)>=0)?
"checked='checked'" : String.Empty)
disabled='disabled'>
@(option.Name)
}
}
options
Name Value
option1 0
option2 1
option3 2
option4 3
option5 4
checkResult
Value
0
3
4
目前的作法,但是是不對的結果...
@helper GetTestItemResult(dynamic[] options, dynamic checkResult) {
var countJ=0;
for(var i = 0; i<options.Length; ++i) {
var option = options[i];
for(int j=countJ; j<checkResult.Option.Count;){
var result = checkResult.Option[j];
if(option.Value==result){
<input type='checkbox' checked='checked' disabled='disabled'>
countJ=countJ+1;
break;
}
else{
<input type='checkbox' disabled='disabled'>
break;
}
@(option.Name)
}
}
}
方法一:
假設 options 跟 checkResult 都是依據 value 排序,那麼用一個變數儲存 checkResult 的「當前位置」,這樣一個迴圈就可以結束了。
方法二:
這個方法不需要排序,而是把 checkResult 轉成 hash table key=>value 那類型的資料型態,這樣查詢該 value 是否存在就很快了。
方法三:
假設不希望依據 value 排序 options ,而只對 checkResult 排序,那麼查詢 value 是否存在於 checkResult 可以用二分搜尋法,可以找看看內建函式是否有支援。
上述三種方法,程式碼大致如下 (我對C#不熟,所以用js表示)
let options=[
{name:'option0',value:0},
{name:'option1',value:1},
{name:'option2',value:2},
{name:'option3',value:3},
{name:'option4',value:4}
];
let checkResult=[0,3,4];
function solution_1()
{
let checkIdx=0;
let checkVal=checkResult[checkIdx];
for(idx in options) {
let key=options[idx].name;
let val=options[idx].value;
if(checkVal === val) {
checkVal=checkResult[++checkIdx];
document.write(key+':checked<br>');
} else {
document.write(key+'<br>');
}
}
}
function solution_2()
{
let valueMap={};
checkResult.forEach(function(val){
valueMap[val]=true;
});
for(idx in options) {
let key=options[idx].name;
let val=options[idx].value;
if(valueMap[val]) {
document.write(key+':checked<br>');
} else {
document.write(key+'<br>');
}
}
}
function solution_3()
{
for(idx in options) {
let key=options[idx].name;
let val=options[idx].value;
if(binarySearch(checkResult, val)!==false) {
document.write(key+':checked<br>');
} else {
document.write(key+'<br>');
}
}
//因為 js 沒有二分搜尋法,所以要自己實作
function binarySearch(srcArray, target) {
//程式碼:略
//回傳找到的 index,如果找不到回傳 false
}
}
謝謝您的幫忙~想先詢問方法一的部份,目前試起來checkIdx會有超過checkResult的索引值的問題,所以我加了一個判斷
if(checkIdx<checkResult.Option.Count){
result=checkResult.Option[checkIndex];
}
,然後,方法一的checkResult應該也要先排序,對嗎?
謝謝潛水員,不知道方便再提問排序的部分嗎?
目前嘗試了以下兩個方式做排序,但都會跳出錯誤訊息,不知道還可以怎麼嘗試呢?
//ToList()與ToArray()都嘗試過了
var aaa = checkResult.Option;
aaa=(
from dynamic result in (dynamic[])aaa
orderby result.Option ascending
select result).ToList();
//
var vvv =
from row in (dynamic[])aaa
orderby row.Chapter ascending
select row;
HashTable跟Dictionary不太一樣哦~XDDD
(註:C#也是有HashTable的,詳細的差異可以去Google一下)
另外,排序的部分可以調整為
var linqOptions = (from option in options
orderby option.Value ascending
select option).ToArray();
dynamic[] checkResultOption = checkResult.Option;
var linqCheckResultOption = (from val in checkResultOption
orderby val ascending
select val).ToArray();
謝謝 YoChen 補充
其實我在最一開始 js 那邊用 hash table 也不是很恰當
我想表達的是 key=>value 那種資料型態
他們底層實作可能各自有不同的方式
但效能上,讀寫資料至少能到 log2(n)
我改一下上面的敘述
謝謝潛水員的幫忙,方法一有成功,目前嘗試往方法二試試看~
另外也謝謝謝謝YoChen的幫忙,轉型的部分還是會有不允許隱含轉換的部分,後來使用明確的轉型即可:
int?[] checkResultOption = checkResult.Option;
如果多選是比較麻煩,
要不然你就先排序吧,
然後再下去找.
但是前提是你兩邊都要有排序.
如果我沒記錯的話
Array.IndexOf 應該理頭是跑回圈的
所以你的code等於是跑2層的巢式迴圈
你要不要試試看能不能改用Dictionary去做, 這樣應該會快一點
如同其他大大所說,您可以參考Dictionary的作法~
@helper GetTestItemResult(dynamic[] options, dynamic checkResult)
{
Dictionary<int, string> dictionary = new Dictionary<int, string>();
foreach (var result in checkResult.Option)
{
dictionary.Add(result, "checked='checked'");
}
foreach (var option in options)
{
string checkedProperty = dictionary.ContainsKey(option.Value) ? dictionary[option.Value] : string.Empty;
<input type='checkbox' @(checkedProperty) disabled='disabled'>
@(option.Name)
}
}