I have a data structure:
*game-board*
#(#() #() #() #() #() #() #())
CL-USER> (test-move)
1
CL-USER> *game-board*
#(("O" "X" . #()) ("O" "X" . #()) ("X" "O" "O" "X" . #())
("X" "O" "X" "O" . #()) ("O" "X" . #()) ("X" . #()) ("X" "O" . #()))
CL-USER> (print-game-board)
("O" "X" . #())
("O" "X" . #())
("X" "O" "O" "X" . #())
("X" "O" "X" "O" . #())
("O" "X" . #())
("X" . #())
("X" "O" . #())
NIL
CL-USER>
My question is how do I get the dimensions of the inner vectors?
(array-dimension game-board 0) returns 7 for the length of the outer vector. How ever I can't figure out how to get the dimensions of the inner vectors.
my code that fills the board is this: (run once for every input)
(defun move (c)
(let ((place (gethash c *col-lookup*)))
(cond ((oddp *turn-count*)
(push "X" (aref *game-board* place))
(incf *turn-count*))
((push "O" (aref *game-board* place))
(incf *turn-count*)))))
I used vectors because I figured I could just push moves onto the board and when checking if the length was less then 4 then just skip the horizontal check for that row.
Am I thinking about optimizing even before I have a solution? That's probably unwise, I probably should just hack something together using a 2d array as suggested.
That is because you you have no inner vectors. Although you start with with a vector of with with 7 vectors, after (test-move) you have a vector with 7 improper lists whose last element is a #(). Can you add the code to test-move so we can help you see what went wrong there?
Btw, I'm guessing you are using a list of lists representation when you want to represent a grid? If so may I suggest using a multidimensional array or just a vector and some helper functions to move from a pair to an index and back.
The inner arrays might not be all have the same dimension, so here's an example that gives you the largest dimension:
(defun inner-dimension (outer-array)
(loop for inner-array being the elements of outer-array
maximize (array-dimension inner-array 0)))
If you want the inner arrays to be all the same size, you should use a single multi-dimensional array instead of an array of arrays.
Related
I am using Common Lisp (SBCL). Currently, I can write a file appending lists. In order to illustrate, let's first define some variables to make it easier to understand:
(defvar example-1 '((d-1 u-1) (i-1) (i-2)))
(defvar example-2 '((d-2 u-2) (i-1) (i-2)))
Now, in the REPL:
CL-USER> (with-open-file (str "/home/pedro/miscellaneous/misc/tests-output/stack-overflow.lisp"
:direction :output
:if-exists :append
:if-does-not-exist :create)
(format str " ~S ~%" example-1))
CL-USER> (with-open-file (str "/home/pedro/miscellaneous/misc/tests-output/stack-overflow.lisp"
:direction :output
:if-exists :append
:if-does-not-exist :create)
(format str " ~S ~%" example-2))
If I go to checkout the file "stack-overflow.lisp", I can see:
((D-1 U-1) (I-1) (I-2))
((D-2 U-2) (I-1) (I-2))
Ok. This is close to what I want.
However, I would like to have everything wrapped in a list:
(
((D-1 U-1) (I-1) (I-2))
((D-2 U-2) (I-1) (I-2))
)
Thus, every time something is "appended" to the file, it should be inside this list. I am changing this because it will make this file easier to read and work on. I will need to filter the elements added.
What do I need to change in with-open-file function to have this output?
Use a single call to WITH-OPEN-FILE and combine everything into a single list.
(with-open-file (str "/home/pedro/miscellaneous/misc/tests-output/stack-overflow.lisp"
:direction :output
:if-exists :overwrite
:if-does-not-exist :create)
(pprint (list example-1 example-2) str))
If you want to append to the list every time you write, you need to read the list, append to the list, then overwrite the file with the updated list.
(defun append-to-list-in-file (filename new-item &aux contents) ;;;;
(setq contents (list)) ;; default in case reading fails
(ignore-errors
(with-open-file (str filename :direction :input)
(setq contents (read str))))
(setq contents (nconc contents (list new-item)))
(with-open-file (str filename :direction :output :if-exists :overwrite)
(write contents :stream str)))
I have two list, A and B and I needed the element of the B list not present in the A list to be in a created list C in Powershell.
(list or array)
A
B
C
One
One
Second
Two
Two
Three
Three
Third
Second
Fourth
third
In this example in C there is the word Second as it is not present in A list.
So it is not the difference between two list, it is one to another, but not the other way around.
I have tested the Compare-Object command but it will exclude the element that are not in B but in A and the ones that are in B but not in A. Which is not what I am looking for.
I also tried something like this :
foreach ($elem in $A) { if ($B -contains $elem) { "there is a match" } }
But it didn't work as I want.
I'm a bit lost a this point.
Use the -notin operator:
$C = #($B) -notin $A
Supplying an enumerable left-hand operand to a scalar comparison operator like -notin turns the operator into a filter - and suddenly it works just like $B |Where-Object { $_ -notin $A }
So finally I decided to use the following command:
Compare-Object -IncludeEqual -ReferenceObject $A -DifferenceObject $B
With the side indicator, I could manage my third table the way I want.
I need to delete specific values in an array (which vary in their index positions), similar to the splice function in javascript.
Example:
set -A ARRAY1 "a" "b" "c" "d" "e"
set -A ARRAY2 "a" "c" "e"
# Expected ARRAY1 after splice: "b" "d"
What I've tried:
I iterated through the arrays to find matches to the values I want deleted, and set them to empty ("").
ITERATION=0
for i in "${ARRAY1[#]}"
do
for j in "${ARRAY2[#]}"
do
if [[ $i == $j ]]
then
ARRAY1[$ITERATION]=""
fi
done
ITERATION=$((ITERATION+1))
done
#ARRAY1 after emptying values: "" "b" "" "d" ""
After that, I made a variable to store the concatenation of the first array's values.
VARIABLE=${ARRAY1[#]}
Then set the array back together again.
set -A ARRAY1 $VARIABLE
# VARIABLE: b d
Now the ARRAY1 has 2 indexes with values "b" and "d" as expected.
echo "ARRAY1: ${ARRAY1[#]}"
# output: ARRAY1: b d
I tried searching for the correct way to do this but couldn't find anything, and I think my solution is not right, even if it seems to work. Is there a correct or better way to do this? Is there a function for this in ksh?
Thanks in advance!
So, what you want to do is take the difference of sets. An indexed array is not a good representation of a set. However, the keys of an associative array is.
Try this:
array1=( "a" "b" "c" "d" "e" )
array2=( "a" "c" "e" )
# declare an associative array
typeset -A tmp
# populate it
for elem in "${array1[#]}"; do
tmp[$elem]=1
done
# remove elements
for elem in "${array2[#]}"; do
unset "tmp[$elem]"
done
# reassign the array with the keys of the assoc. array
array1=( "${!tmp[#]}" )
printf "%s\n" "${array1[#]}"
b
d
Get out of the habit of using ALLCAPS variable names, leave those as reserved by the shell. One day you'll write PATH=something and then wonder why your script is broken.
Using the same notation as the OP, just need one small change to the if/then block to unset the array position:
ITERATION=0
for i in "${ARRAY1[#]}"
do
for j in "${ARRAY2[#]}"
do
if [[ $i == $j ]]
then
unset ARRAY1[$ITERATION]
fi
done
ITERATION=$((ITERATION+1))
done
Here's a ksh fiddle of the above.
A quick dump of the current array:
echo "ARRAY1: ${ARRAY1[#]}"
ARRAY1: b d
Let's say I create an array like this:
for {set i 1} {$i <=4} {incr i} {
lappend run "$i [expr $i+1]"
}
puts "$run"
{1 2} {2 3} {3 4} {4 5}
Now I'd like to find the elements containing 2 and get rid of them so I will be left with
run ={3 4} {4 5}
How could I do it?
First of all: an array is an associative structure in Tcl. What you are creating here is a list.
The usual idiom for filtering out elements from a list is to do something like this (pseudocode):
set result [lmap item $list {if <test-to-keep> {set item} else continue}]
or
set result {}
foreach item $list {if <test-to-keep> {lappend result $item}}
(The lmap command is available in Tcl 8.6 or later, though there is a pure-Tcl version usable in Tcl 8.5 that you can copy and paste into your program mentioned in the links below.)
For this example, you can use this solution:
set result [lmap item $run {if {2 ni $item} {set item} else continue}]
That is, look at each item and if 2 does not occur in it, keep it.
The ni operator is in Tcl 8.5 or later: if you have an older Tcl you should upgrade.
Documentation:
continue,
foreach,
if,
lmap (for Tcl 8.5),
lmap,
ni (operator),
set
I have a proc which finishes off with an array. To return it I use "array get" to retrive a list. This list however does not only contain my array entrys, but also their index:
So my array [ a b c d ] turns into a list { 0 a 1 b 2 c 3 d }
How can i get rid of these index numbers without disturbing the list order?
A few options, apart from using foreach:
# [array get] actually returns a dictionary
puts [dict values $list]
# Could do this too
set entrylist {}
dict for {- entry} $list {
lappend entrylist $entry
}
puts $entrylist
There are more possibilities in Tcl 8.6:
puts [lmap {- entry} $list {set entry}]
(There's also a dict map, but it isn't useful here.)
I like dict values…
The simplest and most basic way I think would be to use a foreach loop:
% set list {0 a 1 b 2 c 3 d}
% set entrylist {}
% foreach {id entry} $list {
% lappend entrylist $entry
% }
% puts $entrylist
a b c d
If you already have an array and work with Tcl 8.5 or later, use dict values:
set arr(0) a
set arr(1) b
set arr(2) c
set arr(3) d
puts [dict values [array get arr]]
But it is better to use a simple list:
set mylist {a b c d}
lset list 1 boo
puts [lindex $mylist 1]
lappend mylist eff
Arrays are associative. Always.