woooee 814 Nearly a Posting Maven

I'm guessing the problem is the redundant calls to getX() and getY(). You do the exact same things 10 times for each boat drawn. That means 120 calls for the 12 boats. Move the call outside the for loops and store the values in variables. Also, the relationship between the "b" variables is constant so you only need one, i.e. instead of b2 you can use b1-12. And similar for the "s" variables. I originally though that perhaps you were supposed to use clone and move, but that wouldn't save anything and may even consume more computer resources.

woooee 814 Nearly a Posting Maven

As Tony said, use a list. This can be run as is as a test.

def selection(number, list_colours, choices):
    while True:
        print("\nValid choices are %s" % (", ".join(list_colours)))
        colour = input("Please enter your %s valid colour: " % (number))

        if (colour in list_colours) and (colour not in choices):
            list_colours.remove(colour)
            return colour, list_colours

        else:
            if colour not in list_colours:
                print("That is not a valid colour")
            if colour in choices:
                print("You have already chosen that colour")
            ## always prints
            print("Please make your selection again")

list_colours = ["red", "blue", "green", "yellow", "magenta", "orange", "cyan"]
choices = []
for number in ["first", "second", "third", "fourth"]:
    choice, list_colours = selection(number, list_colours, choices)
    choices.append(choice)

print ("Choices made list =", choices)
woooee 814 Nearly a Posting Maven

You don't have an input box, you are using the command line so you would just print the error message. You should be able to modify the code you posted on the other forum

while True:
    first_colour = input("Please enter your first valid colour: ")
    if first_colour in list_colours:
        break

    print("Some error message")        ##  added

although I would use a function and a loop to get the colors instead of the 4 separate input statements.

or already existed in you(r) selections

You do not test for this in the code you posted.

woooee 814 Nearly a Posting Maven

In Tkinter is would just be
top.title("New Title")

Or use a Label and Entry box if you have several entries and want a separate title/label for each one.

Ah, you are using input, i.e. the console

x= input("blah blah blah")

then you would just print a line to get something more than "blah blah blah" to print

print("Python Input")
x= input("blah blah blah")
woooee 814 Nearly a Posting Maven

You want to use numberAsked in the while loop instead of
while len(Questions) > 0 :

Also, you can use random.shuffle on the Questions list and then take them in order instead of deleting and checking for length.

woooee 814 Nearly a Posting Maven

See the definition for append mode = "a" Click Here which explains why checking is not necessary.

woooee 814 Nearly a Posting Maven

This doesn't have anything to do with Python. See if the task manager gives a create time or does something simple, like number the processes sequentially so you can tell which is which. Perhaps someone else will know something more about Visual Basic and the Task Manager.

woooee 814 Nearly a Posting Maven

This is not a complete solution but should give you an idea of the program flow

minimum = None
maximum = None
while True:     ## infinite loop so use "break" to exit
        number = input('Please enter a number, or "stop" to stop: ' )
        if number in ["STOP", "stop"]:
            print "breaking while loop"
            break

        """ another way
        if number.isalpha() and number.upper() == "STOP":
            print "isalpha"
            break
        """

        try:
            num = float(number)
            if (minimum) is None or (num < minimum):
                minimum = num
            if (maximum) is None or (num > maximum):
                maximum = num
            print ("Maximum: ", maximum)
            print ("Minimum: ", minimum)

        except ValueError:
            print("Non numeric data was entered.")
        except:
            print("Error with input...")

print ("Final Maximum: ", maximum)
print ("Final Minimum: ", minimum)
woooee 814 Nearly a Posting Maven

Print sys.maxint to see what it says. You are probably going beyond the computer's limit. It depends on your OS: 32 bit or 64 bit. For more precision take a look at the decimal module. If you want to actually do anything with a number than contains 180,000 digits, decimal is the only way to go.

woooee 814 Nearly a Posting Maven

The epoch is OS dependent and has nothing to do with Python. Since we don't know what OS you are using the question can not be answered except to say print gmtime(0) and see what it tells you. 28800 seconds is something like 8 hours so it may be the difference between Greenwich time and local time.

woooee 814 Nearly a Posting Maven

You should be able to do simple debugging like adding print statements to test your code--all code has to be tested.

while (number != "STOP"):
    number = input('Please enter a number, or "stop" to stop: ' )
    if number != "STOP":
        print "breaking out of while loop," number, "not equal 'STOP'"
        break

and

try:
    num = float(number)
except ValueError:
        print("Non numberic data was entered.")
except:
        print("Error with input...")
print "before continue=this line executes no matter what was entered"
continue                            
print "after continue = calc max and min"

Post back with your solution as I think you are completely missing the logic here.

woooee 814 Nearly a Posting Maven

You keep track of the smallest and largest in separate fields. A little trick is to initialize both with the first input value since you don't know the range of the input numbers. For example, if you initialize largest to zero, thinking all numbers will be greater, someone could input negative numbers only.

import random

test_numbers= [random.randint(1, 20) for ctr in range(10)]
print "test_numbers =", test_numbers

largest=0
smallest=0
first_rec=True
for num in test_numbers:
    print num
    if first_rec:     ## initialize with first value input
        smallest = num
        largest = num
        print "begin with smallest and largest =", num
        first_rec=False
    if num < smallest:
        smallest = num
        print "smallest is now", smallest
    elif num > largest:
        largest = num
        print "     largest is now", largest

print "smallest =", smallest, "largest =", largest

And input is generally done something like the following as you can enter a word like "stop" to stop (note this from the instructions "Program will terminate when a non-numeric input is entered"). Plus, if someone wanted to enter -99 as a number, they could not in your original code.

number = 1
while (number.upper() != "STOP"):
    number = input('Please enter a number, or "stop" to stop: ' )
    if number.upper() != "STOP":
        try:
            num = float(number)
        except ValueError:
            print("Non numberic data was entered.")
        except:
             print("Error with input...")

You get the input, then determine if it is stop value or not, and then trigger an except if it is not a float.

woooee 814 Nearly a Posting Maven

It should be obvious that top_down2 should print 2 "dot" triangles and one "star" triangle. Start by getting the "draw the left most triangle" to work, then add the star triangle, then add in the right most triangle. Don't make me sorry I helped you on this.

Note also that you should not hard wire the number of spaces as that will change as my_len changes, as will num_stars (which you can calculate or take the number of dots printed in the final row of the first function). I gave you a hint on how to calculate the number of start spaces for the second function. You will have to figure out the relationship between my_len and the number of start spaces for the first function.

Finally, you pass num_spaces to the function but then re-set to 3 within the function. See "Calling a Function" and "The Return Statement" in this tutorial for info on passing parameters to and getting them from functions. I will not write this program for you.

woooee 814 Nearly a Posting Maven

You are perhaps over thinking this with all of the complicated print statements. You now want a second function with num_dots, num_spaces, and num_stars, and print and then add/subtract from each field accordingly.

def top_down(my_len, spaces):        
    num_dots = 1
    for ctr in range(my_len):
        print ' '*spaces + '.'*num_dots
        num_dots += 2
        spaces -= 1

myChar1 = '*'
myChar2 = '.'
my_len = 3

top_down(my_len, 5)
## as an example only --> but number of spaces will be first number-my_len
## that is 5-3
top_down(my_len, 2) 
woooee 814 Nearly a Posting Maven

One is greater than zero=vowels found
Three is greater than zero=vowels found
etc.

woooee 814 Nearly a Posting Maven

I also want it to display a message when there is no vowel entered

Check the length of a set intersection

test_sentence="The quick brown fox"
v = set(['a', 'e', 'i', 'o', 'u'])
print v.intersection(set(test_sentence))

or set some indicator

msg = input("Enter a sentence: ")
#v = set(['a', 'e', 'i', 'o', 'u'])
a = dict()
vowel_found=False

for letter in "aeiou":
    a[letter] = msg.count(letter)
    if a[letter} > 0:
        vowel_found = True
woooee 814 Nearly a Posting Maven

Use readlines() to get a list of the records. You can then access a record in the list by offset value just like any other list.

woooee 814 Nearly a Posting Maven

Human.makemove is different from Board.makemove (different "name space"). Read the last part of my first reply again. Also, you can replace

        self.board.append((("["+str(self.mark[0])+"]"),("["+str(self.mark[1])+"]"),("["+str(self.mark[2])+"]")))
        self.board.append((("["+str(self.mark[3])+"]"),("["+str(self.mark[4])+"]"),("["+str(self.mark[5])+"]")))
        self.board.append((("["+str(self.mark[6])+"]"),("["+str(self.mark[7])+"]"),("["+str(self.mark[8])+"]")))
    def updateboard(self):
        self.board = []
        self.board.append((("["+str(self.mark[0])+"]"),("["+str(self.mark[1])+"]"),("["+str(self.mark[2])+"]")))
        self.board.append((("["+str(self.mark[3])+"]"),("["+str(self.mark[4])+"]"),("["+str(self.mark[5])+"]")))
        self.board.append((("["+str(self.mark[6])+"]"),("["+str(self.mark[7])+"]"),("["+str(self.mark[8])+"]")))

with

for ctr in range(0, 9):
    self.board.append("[%d]" % (self.mark[ctr]))
woooee 814 Nearly a Posting Maven

Note how the class Board is declared inheriting Human. Also, the init in Board overrides the init in Human so you have to explicitly call it with "super" in new style classes, otherwise the variables in Human's init are not declared.

class Board(Human):
    def __init__(self):
        super(Board,self).__init__()
        self.board = []
        self.mark = []

The statement Human=Human() does nothing. Also, you will not be able to have more than once instance of the Board class with this code. You have redefined it to be an instance instead since the instance and the class have the same name.

def Round(Board):
    Board.makemove()
    Board.addmove()
    Board.printboard()

#startup
Board = Board()   ## Board is no longer a class
Board.makeboard()
Board.printboard()
##Human = Human()

Round(Board)              

## this won't work as "Board" no longer points to a class.
board_2= Board()  
woooee 814 Nearly a Posting Maven
a[0:9:-1]   #why is this not equivilent to a[::-1]

start at a[0], (then -1 = a[-1] which doesn't exist), and go in reverse order until the number is less than 9, which zero is. You want, a[end:start-1:-1], but why even try to reinvent the wheel that is already working.

woooee 814 Nearly a Posting Maven

but I have continuously been getting an error saying that a str object cannot be interpreted as an integer

We have no idea what or where this may be. Post the complete error message which includes the offending line and also state which version of Python you are using as one version will give an error but another version will not for the same line of code.

woooee 814 Nearly a Posting Maven

There is no need to reverse the list twice as you can use -1 in a for loop and start at the back end. Other than that, you have to look at all elements from the back of the list to the first non-0xFFFF however you do it.

woooee 814 Nearly a Posting Maven

To get you started:

for ctr in range(8):
    print 2**ctr,
for ctr in range(6, -1, -1):
    print 2**ctr,
print

for ctr in range(2):
    print 2**ctr,
for ctr in range(0, -1, -1):
    print 2**ctr,
print

for ctr in range(1):
    print 2**ctr,
for ctr in range(-1, -1, -1):
    print 2**ctr,
print

To print with all columns lined up correctly, you will have to calculate the final row first, or store all rows in a list, and then print according to the size of the number in the last row. For n rows, the last row will have n+(n-1) columns=8+7 for 8 rows. To place the 3rd row in the middle for example (3rd row contains 5 numbers), subtract the number from total available columns, 15-5=10. Divide by 2=5, which means row 3 would have 5 'empty' elements, then the 5 calculated elements=1, 2, 4, 2, 1, and then 5 more empty elements.

woooee 814 Nearly a Posting Maven

It is very easy. Just lay it out in a list and print the list. A simplified example.

to_draw = [[" ", "O"],
           [" ", "|"],
           ["\\", " ", "/"],
           [" ", "|"],
           [" ", "|"],
           ["/", " ", "\\"]]

for each_list in to_draw:
    print "".join(each_list)
woooee 814 Nearly a Posting Maven

File "C:\Python27\code\chidimez\tstcode\employees.py", line 951, in OnOpenEdit
sParameter ='Input parameter: %s ' %(sSQL,sParameter)
TypeError: not all arguments converted during string formatting

This statement
sParameter ='Input parameter: %s ' %(sSQL,sParameter)
accepts one parameter (one %s) but you supply 2 parameters (sSQL,sParameter). Note that this line does not appear in the code you posted.

woooee 814 Nearly a Posting Maven

Possibly
I to L = 3 letters, L to P = 4 letters
5 to 9 = 4, 9 to 14 = 5
so
I 9 P 20 =6+14
5 L 14 U =P+5 letters

woooee 814 Nearly a Posting Maven

"I get a Type Error" tells nothing about the why. You must post the entire error message, which shows the offending line and the place in the line where the error occurs. If you use the exact same code to create all boxes using a loop or calling the same function (we don't know), then it is not related to ComboBox creation. Wx has been around for years so I seriously doubt that it has anything to do with Wx code that creates the ComboBoxes, but is instead related to the data, all other things being equal. Once again, print the result of the select statement, and/or use a different set of data to test with which should produce the error at a different place or not at all if your program uses the same code to create all boxes.

Gribouillis commented: well said +13
woooee 814 Nearly a Posting Maven

It gives me that error am I doing something wrong

We don't know what the error is so there is no way to answer other than to ask what happens if nothing is found in the data base. Try printing the look up before adding to the combobox.

woooee 814 Nearly a Posting Maven

To end the game if there is a tie, set the last "while True" to some varialble instead that goes to False when there are no more empty spaces, like

empty_space=True
while empty space:
    input = raw_input("Select a spot: ")
    input = int(input)
    ## rest of code

    empty_space=test_for_empty(board)

To get the computer to try to win requires that you have a list of moves to counter each move of the opponent. Mostly, it is block any compbination of 2 in a row, and don't let the opponent get a corner where they can line up 2 possible wins. You can also simplify the code with lists.

def checkAll(char):
    wins_list = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [1, 4, 7], [2, 5, 8],
                  [0, 4, 8], [2, 4, 6]]
    for each_list in wins_list:
        if check_line(ch, win_list[0], win_list[1], win_list[2]):
            return True

##replaces
if checkLine(char, 0, 1, 2):
    return True
if checkLine(char, 3, 4, 5):
    return True
if checkLine(char, 6, 7, 8):
    return True
if checkLine(char, 0, 3, 6):
    return True
if checkLine(char, 1, 4, 7):
    return True
if checkLine(char, 2, 5, 8):
    return True
if checkLine(char, 0, 4, 8):
    return True
if checkLine(char, 2, 4, 6):
    return True

And similarly for printing the winner, both print the same thing except for "X" or "O" so send the x/o to a function that will print the winner so there is one block of code instead of two.

woooee 814 Nearly a Posting Maven

Your list contains "option 1", etc, not "1".

options = [
'option 1',
'option 2',
'option 3'
]

while True:
    playerOpt = int(input('input '))
    list_test = "option %d" % (playerOpt)
    if list_test in options:
        break  ## exit while()
    print("\n Not a valid entry\n")
woooee 814 Nearly a Posting Maven

It depends on what is in "letters". If your OS is set to ASCII then the latin1 characters will not be found.

woooee 814 Nearly a Posting Maven

You would use len()

print sline[5], type(sline[5]), bool(len(sline[5]))

or eval(), although eval will do anything, so if someone puts "rm *" in the file that is being read, eval will delete the files.

for lit in ["False", "True"]:
    x = eval(lit)
    print x, type(x)
woooee 814 Nearly a Posting Maven

You would bind <Button-3> to the item Click Here. For whitespace, you would have to test event.x and event.y to see if you are over white space or not. This uses a left click to determine the location (event.x, event.y) to draw the snowman, but the principle is the same. For anything more detailed, you will have to post your code. Anyone who has been in any forum for even a short time knows that guessing what the OP is trying to do is a complete waste of time.

from Tkinter import *

class Snowman:
    def __init__(self, root):
        self.cv = Canvas( root, width=300, height=300 )
        self.cv.create_text( 150, 20, text="Left-Click anywhere", \
                             font="Arial" )
        self.draw_snowman(150, 150)

        self.cv.bind( "<Button-1>", self.change_coord )
        self.cv.pack()

    def change_coord(self, event):
        self.cv.delete( self.head, self.body, self.arm1, self.arm2 )
        self.draw_snowman(event.x, event.y)

    def draw_snowman(self, x, y):
        self.head = self.cv.create_oval( x-10, y-10, x+10, y+10, fill="white" )
        self.body = self.cv.create_oval( x-15, y+10, x+15, y+40, fill="white" )
        self.arm1 = self.cv.create_oval( x-20, y+15, x-10, y+30, fill="white" )
        self.arm2 = self.cv.create_oval( x+20, y+15, x+10, y+30, fill="white" )

top = Tk()
Snowman(top)
mainloop()
woooee 814 Nearly a Posting Maven

Generally you pass the value to the function as you want the code "encapslated", i.e. the class does everything.

class Foot:
    def __init__(self,mov,posx,posy,targx,targy):
        # self.mov is soldier's movement speed, currently not implemented
        self.mov = mov
        # self.x and self.y are soldier's position
        self.x = posx
        self.y = posy
        # self.targx and self.targy are soldier's x and y target destinations
        self.targx = targx
        self.targy = targy

    def advancex(self, targx):
        # advancex(self) adjusts soldier's x position to match the target x position 
        if self.x > targx:
            self.x = self.x - 1
        elif self.x < targx:
            self.x = self.x + 1

        """ the rest does nothing
        else:
            self.x = self.x
        return self.x
        """

sold1 = Foot(0, 4, 6, 0, 1)
sold1.advancex(1)
print "x is now", sold1.x
sold1.advancex(-2)
print "x is now", sold1.x

You can change the variables outside of the class, but that is not the preferred way.

class Foot:
    def __init__(self,mov,posx,posy,targx,targy):
        # self.mov is soldier's movement speed, currently not implemented
        self.mov = mov
        # self.x and self.y are soldier's position
        self.x = posx
        self.y = posy
        # self.targx and self.targy are soldier's x and y target destinations
        self.targx = targx
        self.targy = targy

    def advancex(self):
        # advancex(self) adjusts soldier's x position to match the target x position 
        if self.x > self.targx:
            self.x = self.x - 1
        elif self.x < self.targx:
            self.x = self.x + 1

sold1 = Foot(0, 4, 6, 0, 1)
sold1.targx = 1
sold1.advancex()
print "x is now", sold1.x
sold1.targx = -2
sold1.advancex()
print "x is now", …
woooee 814 Nearly a Posting Maven

Try splitting the original on the newline and working with the resulting list.
split_str=orig_string.split("\n")

woooee 814 Nearly a Posting Maven

I am answering the question as asked. If that means that a I am not your robot then so much the better.

woooee 814 Nearly a Posting Maven

You have the range endings reversed and you want to start at +1 on the inner loop.

for x in range(0, len(a)-1):
    for j in range(x+1, len(a)):

Also you swap every time there is a difference instead of once per loop.

import random

a=[random.randint(1, 100) for ctr in range(20)]
print a
#
for x in range(0, len(a)-1):
    largest = x
    for y in range(x+1, len(a)):
        if a[largest] < a[y]:
            largest = y
    if largest > x:
        temp = a[largest]
        a[largest] = a[x]
        a[x] = temp
print a
woooee 814 Nearly a Posting Maven

You should test for whatever in the program, and if true then call the function or class in the imported module. As stated previously, this is a design problem not a programming problem. A simple example from you would help.

woooee 814 Nearly a Posting Maven

You don't check the last element, so possibly want to use

        for x in range(0,len(mylist)-1):
            ## don't compare "x" to itself and go to the end of the list
            for y in range (x+1,len(mylist)):

This will give you a count for each item, so you will get three different "3" counts. Since the list is sorted, you can store the number in a separate variable and compare this number with previous number and only count if they are different.

woooee 814 Nearly a Posting Maven

We don't have the code that creates "maze" so have no idea what kind of object it is, but you should access it the same way whatever the object.
if maze[row-1,col] == 'O' or 'F': --> this doesn't make sense to me and will always be "True"
if maze(row,col) == 'F': --> this implies that maze is a function

And you should test your code as you go along instead of trying to figure out what is wrong with 100+ lines of code.

woooee 814 Nearly a Posting Maven

When I run the code, it results in this error

File "./test_1.py", line 110, in <module>
l,w=eval(input("Please enter length and width of room #"+str(x)))
TypeError: eval() arg 1 must be a string or code object

eval() is used to evaluate formulas or code so is not appropriate here and is generally considered bad practice as it will run anything that is entered i.e someone can enter a command to delete all of your files if they want to. Get the program to run first and then work on the room number problem. If you are using Python2.X (you didn't say) then input returns an integer so you can't separate the entries as that requires entering a non-integer character like a comma.

Formatting and concatenating strings http://www.diveintopython.net/native_data_types/formatting_strings.html
A Python2.x example

for i in range (5):
    x=x+1
    entry=raw_input("Please enter length and width of room ")
    l,w = entry.split(",")
    sum=sum+int(l)*int(w) 
woooee 814 Nearly a Posting Maven

You call randomNumGenerator() twice, once in each of the two functions and so are working with two different values (althought it is possible to return the same value twice). If you are going to tutor then you should try to follow the Python Style Guide and stop using the half-camelCase naming convention.

Also, in this code

   for u in userPos:
       for r in randPos:
           if(u == r):
               if(userPos.index(u) == randPos.index(r)):
                    posCount = posCount + 1

index will only find the first letter's position so if you have multiples of the same letter it will not work as expected. In addition

for u in userPos:
       for r in randPos:
           if(u == r):

will compare "u" to every postion in randPos, so if there is only one "2" in userPos and 2 in randPos it will report two postions that are the same which is not true. You want to compare the first postions of both strings/lists, then the second postion of both, etc. Finally, why do you convert to a string in randomNumGenerator() and then convert it back to it's original form, a list, in the functions?

woooee 814 Nearly a Posting Maven

For completeness, you can also use a dictionary

def F1(*args):
    if len(args) == 4:
        to_dict ={}
        to_dict["v"]=args[0]
        to_dict["u"]=args[1]
        to_dict["a"]=args[2]
        to_dict["t"]=args[3]

        for key in to_dict:
            print key, to_dict[key]     ## while testing
            if to_dict[key] == None:
                ## etc
woooee 814 Nearly a Posting Maven

Copied to preserve the code tags.

def program(List, Name, Detail):
    for entry in List:
        if entry[0] == Name:
            ## changed to add to the entry containing "Name" not 
            ## entry[1] as it is [Detail, Counter] so would become
            ## [Detail, Counter, [Detail_2, Counter_2]]
            entry.append([Detail,Counter])  ## "Counter" has not been declared
#-----------------------------------------------------------
#   return=You exit the function here if the name is found,
#   i.e. the following code is never reached and so is not
#   the problem
#-----------------------------------------------------------
            return
           
    List.append ([Name,[Detail]])
    for entry in index:           ## "index" is never declared
        if entry[0] == Name:
            entry[1].append(Counter)
woooee 814 Nearly a Posting Maven

In addition, the slow down also comes from using a list. Use a set or dictionary to store and lookup the id. It is something like 1000 times faster.

woooee 814 Nearly a Posting Maven

Receive the variables as a tuple and then use each item as your variable.

def test_num_variables(*args):
    print "number of variables =", args, type(args), len(args)
    os = -1
    if None in args:
        os=args.index(None)
        print "finding None =", os, args[os]
    else:
        print "None was not found"
        return

    ## assumes that the check for numbers has already been done
    total = 0
    for idx in range(len(args)):
        if idx != os:
            total += args[idx]
    print "adding test =", total

test_num_variables(1, 3, 5, None)
woooee 814 Nearly a Posting Maven

Your code looks like it should work fine. Post back if you run into further problems.

woooee 814 Nearly a Posting Maven

I need to find the records that contain duplicate <id> tags.

Which duplicate records do you want to delete, the first or last? In any case, with a 3GB file you probably want to iterate over the file one record at a time instead of trying to read it into memory. And just for clarity, we are assuming that one record group = from <tag> to </tag>, so you first want to store one record group and either save the id number and write the group to a file, or ignore the group if you want to delete it.

woooee 814 Nearly a Posting Maven

IMHO the only time to use the keyword "is" is when you want to test that 2 objects point to the same block of memory, otherwise you can get unexpected results. This is a simple example of equal returning a True and is returning a False for the same comparison.

x="abc"
y = "a"
print "is", x is y, x, y     ## False
print "==", x==y, x, y       ## False

y += "bc"
print "\nis", x is y, x, y   ## False
print "==", x==y, x, y       ## True
woooee 814 Nearly a Posting Maven

Thanks for both of these good solutions guys.

Also, woooee, why is using "i", 'I' and "O" bad?

They can look like numbers and you are interviewing, usually, with someone who is interested in code that can be easily maintained, so they don;t want anything that can be confusing. In fact single letter variables are not a good idea at any time. You should use something more descriptive, outer and inner, or row and col, etc.