2017-10-16 21 views
1

値:TCLは、同一のリストにカウンターを追加し、私は値のリストを持っている

set unnumbered [list 101 101 101 102 102 103 104 105 105 105 106] 

私はこのような、その後の同じ値にカウンターを追加したい:

numbered [ 101.1 101.2 101.3 102.1 102.2 103 104 105.1 105.2 105.3 106] 

これまでのところ、私が試してみました以下:

set unnumbered [list 101 101 101 102 102 103 104 105 105 105 106] 
set numbered [list ] 
set previous [lindex $unnumbered 0] 
set subcounter 1 

foreach current $unnumbered { 

     if { $current eq $previous } { 
       lappend numbered $current.$counter 
       set previous $current 
       incr subcounter 
     } else {   
       lappend numbered $current 
       set previous $current 
       set subcounter 1 
       } 
} 

結果はほぼ必要です。

101.1 101.2 101.3 102 102.1 103 104 105 105.1 105.2 106 

最初の値を除いて、カウンタは遅くまでカウントします。最初の102件は ".1"です。

これはどのように修正できますか?

答えて

0

問題は、数字がnumberedに追加された時点でコードに十分な情報がないことです。情報を最初に取得し、それを適用します。

まず、各項目は、その数が発生$unnumbered$unnumbered中で固有番号と指標の一つからなるリストであるリストを作成します。、それらの項目のそれぞれについて

lmap n [lsort -unique $unnumbered] { 
    list $n [lsearch -all $unnumbered $n] 
} 
# => {101 {0 1 2}} {102 {3 4}} {103 5} {104 6} {105 {7 8 9}} {106 10} 

を分割アイテムをn =数字に、indices =インデックスにします。あなたが持っているインデックスの数を確認してください。複数のインデックスについては、次のように列挙された番号を追加します。

set i 0 
foreach index $indices { 
    lappend numbered $n.[incr i] 
} 

を単一の指標については、単に数を追加:

lappend numbered $n 

全体のプログラムは次のようになります。

set unnumbered [list 101 101 101 102 102 103 104 105 105 105 106] 
set numbered [list] 

foreach item [lmap n [lsort -unique $unnumbered] { 
    list $n [lsearch -all $unnumbered $n] 
}] { 
    lassign $item n indices 
    if {[llength $indices] > 1} { 
     set i 0 
     foreach index $indices { 
      lappend numbered $n.[incr i] 
     } 
    } else { 
     lappend numbered $n 
    } 
} 

ドキュメント: > (operator), foreach, if, incrlappendlassignlistllengthlmap (for Tcl 8.5)lmaplsearchlsortset

あなたはlmapを持っていない場合は、上記のリンクを参照してください。 lassignがない場合は、代わりに

foreach {n indices} $item break 

を使用してください。

ETA「シングルトンの数字には何の指標」の要件を緩和することができた場合は、1は、このようにそれを行うことができます:

set previous {} 
lmap num $unnumbered { 
    if {$num ne $previous} { 
     set i 0 
    } 
    set previous $num 
    format %d.%d $num [incr i] 
} 

別の変形。Jerryの2番目の提案とよく似ていますが、これを提出するまでは私は見ませんでした。正直です。これは、$unnumberedの要素が空の文字列でないことを前提としています。

set numbered [list] 
set rest [lassign $unnumbered current next] 
set i 0 
while 1 { 
    if {$current eq $next} { 
     lappend numbered $current.[incr i] 
    } else { 
     if {$i > 0} { 
      lappend numbered $current.[incr i] 
      set i 0 
     } else { 
      lappend numbered $current 
     } 
     set current $next 
    } 
    if {$next eq {}} break 
    set rest [lassign $rest next] 
} 
0

別のアプローチ:少し単純である配列を使用して、あなたがこれまでに

set unnumbered [list 101 101 101 102 102 103 104 105 105 105 106] 
set count [dict create] 
set numbered {} 
foreach num $unnumbered { 
    dict incr count $num 
    lappend numbered "$num.[dict get $count $num]" 
} 
puts $numbered 
101.1 101.2 101.3 102.1 102.2 103.1 104.1 105.1 105.2 105.3 106.1 

を見てきたものの数を保つために辞書を維持する:事実を活用してそのincr戻って新たなカウント

set numbered {} 
array set count {} 
foreach num $unnumbered {lappend numbered "$num.[incr count($num)]"} 

OK、シングルトンエントリに接尾辞を付けるべきではないという要件を忘れました。

set count [dict create] 
foreach num $unnumbered {dict incr count $num} 
set numbered {} 
foreach num [dict keys $count] { 
    set c [dict get $count $num] 
    if {$c == 1} { 
     lappend numbered $num 
    } else { 
     for {set i 1} {$i <= $c} {incr i} { 
      lappend numbered "$num.$i" 
     } 
    } 
} 
puts $numbered 
101.1 101.2 101.3 102.1 102.2 103 104 105.1 105.2 105.3 106 

それとも、これは

set count [dict create] 
foreach num $unnumbered {dict incr count $num} 
foreach key [dict keys $count] { 
    if {[dict get $count $key] == 1} { 
     set count [dict remove $count $key] 
    } 
} 

set numbered {} 
foreach num [lreverse $unnumbered] { 
    if {![dict exists $count $num]} { 
     lappend numbered $num 
    } else { 
     lappend numbered "$num.[dict get $count $num]" 
     dict incr count $num -1 
    } 
} 
set numbered [lreverse $numbered] 
puts $numbered 
101.1 101.2 101.3 102.1 102.2 103 104 105.1 105.2 105.3 106 
+0

良い解決策ですが、シングルトン番号をインデックスに残しておきたい場合は役に立ちません。 –

+0

そう、その要件を逃した。 –

0

アンO(nは元の順序を維持します。それかもしれ再順序最初のリストがあり、これはですが、 )ソリューション(単一ループ)であり、最初に実装したかった方法それをメンター:

set unnumbered [list 101 101 101 102 102 103 104 105 105 105 106] 
set numbered [list] 
set previous "" 
set subcounter 1 

foreach current $unnumbered { 
    if {$previous == ""} { 
    # First, do nothing except set $current to $previous later below 
    } elseif {$previous == $current} { 
    lappend numbered $previous.$subcounter 
    incr subcounter 
    } else { 
    if {$subcounter > 1} { 
     lappend numbered $previous.$subcounter 
    } else { 
     lappend numbered $previous 
    } 
    set subcounter 1 
    } 
    set previous $current 
} 

if {$subcounter > 1} { 
    lappend numbered $current.$subcounter 
} else { 
    lappend numbered $current 
} 

最後ifが最後の数字のために必要とされるように、ループは基本的に、numberedリストに遅くつの番号を追加します。もちろん、これはunnumberedがソートされていることがわかっている場合にのみ機能します。


編集:実際これはさらに近くです!すでに$previousを得ることができるので、リストの次の要素から最後の要素の後ろにループすることができます(lindexに範囲外のインデックスが指定されている場合は空白になります。ここに)。

set unnumbered [list 101 101 101 102 102 103 104 105 105 105 106] 
set numbered [list] 
set previous [lindex $unnumbered 0] 
set subcounter 1 

for {set i 1} {$i <= [llength $unnumbered]} {incr i} { 
    if {$previous == [lindex $unnumbered $i]} { 
    lappend numbered $previous.$subcounter 
    incr subcounter 
    } else { 
    if {$subcounter > 1} { 
     lappend numbered $previous.$subcounter 
    } else { 
     lappend numbered $previous 
    } 
    set subcounter 1 
    } 
    set previous [lindex $unnumbered $i] 
} 
関連する問題