Tcl proc для вывода списка или массива

Я новичок в массивах Tcl. У меня следующий вопрос.

У меня есть прямоугольник с двумя рядами R1 и R2. Каждая из этих строк имеет 8 различных значений. Я хочу вернуть эти 16 значений (координаты x и y) либо в текстовом файле, либо в виде вывода списка из процедуры. Я читал несколько предыдущих сообщений о том, что Tcl proc не может выводить массив, если мы не используем dict. Итак, я попытаюсь нарисовать картинку, чтобы вы могли лучше понять мой вопрос.

R1  x1y1    x2y2        ... x8,y8
R2  x9,y9       ...     x16, y16

Ожидаемый результат, когда я запускаю процедуру либо в командной строке, либо в файле с фиктивными значениями в качестве примера

$>    (1,2)  (2,3) (3,4) ....... (7,8)
      (9,10) (10,11) ......... (15,16)

Это то, что я пробовал, и я получаю те результаты, которые мне нужны. Но это жестко запрограммировано для двух строк. Я хочу, чтобы он мог определять, сколько строк там, а затем соответственно выводить количество строк.

proc getPointList {rect_boundary rowOffset colOffset rowIncr colIncr } {
 set cordlist $rect_boundary

 set xl  [lindex $cordlist 0]
 set yl  [lindex $cordlist 1]
 set xh  [lindex $cordlist 2]      
 set yh  [lindex $cordlist 3]

 set list "" ;

 for {set y [expr {$yh - $colOffset}]} {$y >= [expr {$yl + $colOffset}]} { incr y $colIncr } {

    for {set x [expr {$xl + $rowOffset}]} {$x <= [expr {$xh - $rowOffset}]} { incr x $rowIncr } {

            set list "$list $x $y" ;
            puts "Value of x is: $x"; puts "\t Value of y is: $y" ;  
        } 
 }
return $list  
}

set rect_boundary {10 15 100 40}     # xl yl xh yh
set rowOffset 5
set colOffset 5
set rowIncr 10
set colIncr 15

Некоторая логика, которую мне нужно реализовать в этом коде на основе yh-yl и xh-xl, чтобы вычислить высоту и ширину прямоугольника и, соответственно, выходные строки

Команда для вызова процедуры

$> getPointList $rect_boundary $rowOffset $colOffset $rowIncr $colIncr

Просто для вашего понимания внутри прямоугольника в определенной строке есть восемь точек x, y. Смещение по x - это первая точка x в строке от левой или правой границы, после чего все точки разделяются значением приращения, которое я называю rowIncr. То же самое верно и для столбца.

Ожидаемый результат: это то, что делает приведенный выше код, но он жестко запрограммирован для двух строк. Я хочу увеличить и реализовать логику, если строки и столбец являются переменными.

$>  R1:  (15 40) (25 40) (35 40) (45 40) (55 40) (65 40) (75 40) (85 40) (95 40)
    R2:  (15 15) (25 15) (35 15) (45 15) (55 15) (65 15) (75 15) (85 15) (95 15)

Прямоугольное изображение для большей четкости, поскольку эта штука не позволяет мне обновлять изображения

__________________________________________________________________________ (100,40)
|                       |- 5                                              |
|   .          .        .       .        .       .        .        .      |
|                               |- 15                                     |
|-5-.          . --10---.       .        .       .        .        .      |
|                                                                         |
|_________________________________________________________________________|
(10,15)    

Для Джерри:

Case1  rowIncr 10 colIncr 20
__________________________________________________________________________ (80,40)
|                       |- 5                                              |
|   .          .        .       .        .       .        .        .      |
|                               |- 20                                     |
|-5-.          . --10---.       .        .       .        .        .      |
|                                                                         |
|_________________________________________________________________________|
(10,10)

Case2   rowIncr 20 colIncr 35
_________________________________________________ (100,70)
|                       |- 5                     |
|   .          .        .       .        .       |
|                               |- 35            |
|-5-.          . --20---.       .        .       |
|              |                         |-5     |
|________________________________________________|
(10,25)

и так далее ...


person user2643899    schedule 19.08.2013    source источник
comment
Я так понимаю, что вы хотите извлечь координаты из прямоугольника? Разделены ли координаты символом табуляции, а каждая координата x и y - запятой?   -  person Jerry    schedule 20.08.2013
comment
Привет, Джерри: Мне нужны только координаты xy внутри прямоугольника. I Со значениями, разделенными запятыми, или без них - не вопрос. Как только я смогу это сделать, я могу использовать разделение, чтобы выделить значения xy, а также удалить запятую. Запятая, использованная в моем вопросе, является примером, если ее нет, то лучше.   -  person user2643899    schedule 21.08.2013
comment
Привет, не могли бы вы также ввести образец ввода со всеми числами и тем, как вы вызываете процедуру? У меня проблемы с пониманием вашего фактического ввода и требуемого вывода с этой процедурой ... :(   -  person Jerry    schedule 21.08.2013
comment
Мы хотели бы помочь, поэтому, пожалуйста, помогите нам, показав нам, как выглядит ввод и ожидаемый вывод, как вы читаете ввод, передайте его своей функции. Вы заявили, что ваш ввод выглядит как 8 чисел в строке, но ваша процедура принимает только 5 - первое - это список из 4 - очень запутанно.   -  person Hai Vu    schedule 21.08.2013
comment
Хай Ву и Джерри: процедура принимает аргументы, я задам свой вопрос, как вызвать процедуру и образец вывода   -  person user2643899    schedule 22.08.2013


Ответы (3)


Хорошо, я думаю, теперь я понимаю, что вы пытались сделать, и я думаю, что ваша процедура работала бы для любого количества строк после некоторого исправления:

set output [open "output.txt" w]

proc getPointList {rect_boundary rowOffset colOffset plist} {
    global output

    set cordlist $rect_boundary
    set xl  [lindex $cordlist 0]
    set yl  [lindex $cordlist 1]
    set xh  [lindex $cordlist 2]      
    set yh  [lindex $cordlist 3]

    set xpoints [llength [lindex $plist 0]]
    set ypoints [llength $plist]
    set rowIncr [expr {($xh-$xl-2*$rowOffset)/($xpoints-1)}]
    set colIncr [expr {($yh-$yl-2*$colOffset)/($ypoints-1)}]

    set count 0
    set list ""

    for {set y [expr {$yh - $colOffset}]} {$y >= [expr {$yl + $colOffset}]} {incr y -$colIncr} {

        for {set x [expr {$xl + $rowOffset}]} {$x <= [expr {$xh - $rowOffset}]} {incr x $rowIncr} {
            lappend list "($x,$y)"
        }
        incr count
        puts $output "R$count: [join $list " "]"
        set list ""
    }
}

set plist {{A B C D E} {A B C D E} {A B C D E} {A B C D E} {A B C D E}}
set rect_boundary {0 0 100 100}
set rowOffset 0
set colOffset 0

getPointList $rect_boundary $rowOffset $colOffset $plist

close $output

Я изменил colIncr, чтобы добавить больше строк.

В первом цикле я использовал incr y -$colIncr, потому что это фактически уменьшение, если вы начнете с более высокой координаты y.

Я также изменил структуру вывода, чтобы она соответствовала той, которую вы искали. Приведенный выше фрагмент возвращает координаты:

R1: (0,100) (25,100) (50,100) (75,100) (100,100) 
R2: (0,75) (25,75) (50,75) (75,75) (100,75) 
R3: (0,50) (25,50) (50,50) (75,50) (100,50) 
R4: (0,25) (25,25) (50,25) (75,25) (100,25) 
R5: (0,0) (25,0) (50,0) (75,0) (100,0)

РЕДАКТИРОВАТЬ: добавлены переменные смещения, пустая последняя строка и переменные столбцы в каждой строке.

proc getPointList {rect_boundary uRowOffset lRowOffset uColOffset lColOffset plist} {
    set cordlist $rect_boundary
    set xl  [lindex $cordlist 0]
    set yl  [lindex $cordlist 1]
    set xh  [lindex $cordlist 2]      
    set yh  [lindex $cordlist 3]

    set xpoints 0
    foreach r $plist {
        if {[llength $r] > $xpoints} {set xpoints [llength $r]}
    }

    set ypoints [llength $plist]
    set rowIncr [expr {($xh-$xl-$lRowOffset-$uRowOffset)/($xpoints-1)}]
    set colIncr [expr {($yh-$yl-$lColOffset-$uColOffset)/$ypoints}]

    set count 0
    set list ""

    for {set y [expr {$yh - $uColOffset}]} {$y >= [expr {$yl + $lColOffset}]} {incr y -$colIncr} {
        set x [expr {$xl + $lRowOffset}]
        foreach n [lindex $plist $count] {
            lappend list $x $y
            incr x $rowIncr
        }
        incr count
        if {$count == $ypoints} {return $list}
    }
}

set plist {{A B C D X} {E F G H} {I K L} {M N}}
set qlist 1
foreach n $plist {
    set pattern$plist $n
    incr qlist
}

set rect_boundary {0 0 100 100}
set upperRowOffset 0
set lowerRowOffset 0
set upperColOffset 0
set lowerColOffset 0

set pointList [getPointList $rect_boundary $upperRowOffset $lowerRowOffset $upperColOffset $lowerColOffset $plist]

set count 1
foreach sub_list $plist {
    foreach n $sub_list {
        set pattern$count $n
        incr count
    }
}

set count 1
foreach {a b} $pointList {
    set text "pattern$count"
    puts "command -point $a,$b -text [set $text]"
    incr count 
}
person Jerry    schedule 22.08.2013
comment
Спасибо, Джерри !! Ценить это. Я обычно ставлю знак - для учета декремента при указании набора colIncr -5, который я просто забыл упомянуть во фрагменте описания проблемы, но вы правы. Позвольте мне попробовать этот код и посмотреть, как он работает. - person user2643899; 22.08.2013
comment
Еще одна вещь, Джерри: что мне делать, если мои rowIncr и colIncr меняются динамически от случая к случаю. ?? - person user2643899; 24.08.2013
comment
@ user2643899 Это не должно быть проблемой. Просто убедитесь, что обновленные colIncr и rowIncr передаются в proc. - person Jerry; 24.08.2013
comment
@ user2643899 Или вы имеете в виду, что они меняются на один и тот же прямоугольник? (Как в первой строке 5, затем 10, затем 5 и т. Д. И аналогично для столбцов) - person Jerry; 24.08.2013
comment
Джерри: Да, я знаю, что могу передать обновленную версию в процедуру, я имел в виду динамическое изменение в соответствии с вашим комментарием выше. Как ne прямоугольник с rowIncr и Column Incr, скажем, 10, например, и второй прямоугольник с RowIncr и ColIncr, равными 15 и 20. Третий прямоугольник rowIncr 35 и ColIncr 68 ... и т. Д. И т. Д. - person user2643899; 26.08.2013
comment
@ user2643899 Я не уверен, что вы имеете в виду, но если я правильно понял, вы можете создать процедуру для создания нескольких прямоугольников, которая будет вызывать getPointList для каждого прямоугольника с указанными значениями. Если вы можете привести пример того, как кто-то воспользуется этим, это может прояснить ситуацию. - person Jerry; 26.08.2013
comment
Джерри: Я не хочу создавать несколько прямоугольников. Фактически, мне будет предоставлено несколько прямоугольных таблиц в качестве входных данных, на которых я намереваюсь запустить свою функцию getPointList. Для rowIncr и ColIncr нет определенных значений, я вычисляю их на основе прямоугольников разного размера. Настоящий вопрос заключается в том, как попросить код Tcl вычислить те значения, которые изменяются в зависимости от границы прямоугольника по ширине и высоте. Могу привести еще примеры, если непонятно. - person user2643899; 26.08.2013
comment
@ user2643899 Хорошо, я так понимаю, вам даны границы прямоугольника, верно? Кроме того, если вам не дается rowIncr или colIncr, я предполагаю, что вам дано количество строк и столбцов, верно? Кроме того, было бы желательно привести еще несколько примеров, если то, что я сказал в этом комментарии, не соответствует вашей точке зрения! - person Jerry; 26.08.2013
comment
Джерри: Количество строк, я рассчитываю что-то и сохраняю это в переменной. Например, установите row_list {{1 2 3} {13 14 15} {20 21 22}}. Теперь установите numberof_rows [llength $ row_list]. Это вернет 3. Столбец автоматически рассчитывается из них, если я разделю приведенный выше список на 3 строки, тогда у меня будет количество столбцов, которое мне нужно (в данном случае: 3). - граница прямоугольника. Я добавлю для вас более подробную информацию в моем оригинальном вопросе выше - person user2643899; 26.08.2013
comment
Пожалуйста, приходите в чат-комнату прямоугольников Tcl всякий раз, когда у вас есть возможность, или отправьте мне пинг, я буду периодически проверять его, и мы сможем синхронизировать соответственно - person user2643899; 31.08.2013
comment
Я включил уведомление на рабочем столе, не могли бы вы встретиться со мной в чате - person user2643899; 16.09.2013
comment
Из-за того, что вы меняете разрешение на комнату, я набираю сообщения, но это не позволяет мне публиковать сообщения, в которых говорится: rety / cancel - person user2643899; 20.09.2013
comment
не могли бы вы зайти в чат? - person user2643899; 13.11.2013
comment
@ user2643899 Привет! Извините, я добровольно отключил все от Интернета, когда начались мои экзамены :( Я только что увидел ваше сообщение и с сегодняшнего дня я более доступен. - person Jerry; 09.12.2013
comment
Эй, нет проблем, парень, мне действительно нужна была твоя помощь, но теперь о ней позаботились. Как прошли экзамены? (чат заморожен) - person user2643899; 25.01.2014
comment
@ user2643899 Было неплохо, но мне нужно дождаться результатов. Я сделал еще один. - person Jerry; 25.01.2014

Вам решать, как организовать вложенные списки. В простейшей форме верните один список:

set result {x1 y1 x2 y2 ... x16 y16}

Или у вас может быть список из двух строк:

set result {
    {x1 y1 x2 y2 ... x8 y8}
    {x9 y9 x10 y10 ... x16 y16}
}

Или, что более сложно: каждая пара представляет собой подсписок:

set result {
    { {x1 y1} {x2 y2} ... }
    { {x9 y9} {x10 y10} ... }
}

Я не думаю, что вы хотите использовать в этом случае массив. К вашему сведению, «массив» в TCL эквивалентен хешу на других языках.

person Hai Vu    schedule 19.08.2013
comment
Привет, Хай Ву: Вы только что жестко запрограммировали значения в виде списка, и после этого любой может использовать put или return. На самом деле, я не этого хочу. Но спасибо за ваше предложение. - person user2643899; 21.08.2013

Ну а с Tcl 8.6

proc parsedata {input} {
    lmap a [split $input \n] {
        lmap b [split $b \t] {
           regexp {x(\d+),?\s*y(\d+)} $b -> c d
           list $c $d
        }
    }
}

Теперь вы можете обрабатывать данные, например:

foreach line [parsedata $input] {
    puts [lmap pair $line {
        expr {"([lindex $line 0],[linedex $line 1])"}
    }
}
person Johannes Kuhn    schedule 20.08.2013
comment
Привет, Йоханнес, спасибо за фрагмент кода. Однако это поможет мне разобрать код. Я не использую Tcl 8.6, поэтому у меня он все равно не сработает. - person user2643899; 21.08.2013