0

So I have a code to give a position of a character in a text file, using my function code that looks like this

#this is defined function
def return_position(arr, search_for=[''], base=1):
    dim = ()
    arr = [str(arr) for arr in arr]
    for search in search_for:
        for sr in range(len(arr)):
            s = arr[sr]
            for cr in range(len(s)):
                c = s[cr]
                if c == search:
                    dim += [(cr+base, sr+base)]
    return dim

In order to get the list of file, I used .readlines() because it's containing a list and will get the expected result, so I did

#open the file and read it as a list
textlist = open('testfile.text', 'r').readlines()
#textlist = ['Build a machine\n', 'For the next generation']

#print the return_position as a lines
print(''.join(return_position(textlist, search_for=['a', 'b'])))

In testfile.txt

Build a machine
For the next generation

Expected result

(1, 1)
(7, 1)
(10, 1)
(19, 2)

But why it's returning

TypeError can only concatenate tuple (not "list") to tuple

  • This is not related to your question, but consider giving the loop variable in `arr = [str(arr) for arr in arr]` a name that's different to the thing you're iterating over. :) – NPE Oct 11 '19 at 05:50
  • @NPE what do you mean? –  Oct 11 '19 at 05:51
  • You have three different things called `arr` in that one line of code: (1) the thing you're iterating over; (2) the loop variable; (3) the name given to the result of the list comprehension. It's OK (customary even) for (1)+(3) to have the same name. It is good practice to give (2) a different name, e.g. `arr = [str(val) for val in arr]`. – NPE Oct 11 '19 at 05:53
  • If you are just trying to find the position of the string you can iterate through the lines with one for loop and do .index() to get the position. https://www.programiz.com/python-programming/methods/string/index Also as a suggestion try to make to your code readable by using proper variable names. – badc0re Oct 11 '19 at 07:02
  • @badc0re no no, if you use object.index(x) it will only return one value and that is not what I wanted –  Oct 11 '19 at 07:07

3 Answers3

0
dim += [(cr+base, sr+base)]

This line won't work if dim is a tuple.

Turn this

dim = ()

into

dim = []

A tuple is an immutable ordered sequence. You can't append stuff to it. So use a list.

Ref: https://docs.python.org/3/library/stdtypes.html#typesseq

rdas
  • 20,604
  • 6
  • 33
  • 46
0

In your code dim is a tuple and tuples are immutable (i.e. cannot be modified after they're constructed).

You'll need to turn dim into a list to be able to append to it:

dim = []
NPE
  • 486,780
  • 108
  • 951
  • 1,012
0

As the other answers point out already a tuple is immutable and can not be changed. That, however, does not answer your question because you are not trying to change a tuple, you are trying to concatenate a tuple and a list. Python does not know whether you would want a tuple or a list as a result therefore it raises the TypeError.

Concatenating two tuples works:

(1,2) + (3,4)  # result: (1, 2, 3, 4)

Concatenating two lists works as well:

[1,2] + [3,4]  # result: [1, 2, 3, 4]

Only the mixture of tuple and list causes the problem:

[1,2] + (3,4)  # raises TypeError

Therefore (as the other answers point out already) changing the data type of either operand would solve the problem.

I would suggest using a list and append to it instead of concatenate for efficiency reasons:

def return_position(arr, search_for=[''], base=1):
    dim = []  # changed this line
    arr = [str(arr) for arr in arr]
    for search in search_for:
        for sr in range(len(arr)):
            s = arr[sr]
            for cr in range(len(s)):
                c = s[cr]
                if c == search:
                    dim.append((cr+base, sr+base))  # changed this line
    return dim

textlist = ['Build a machine\n', 'For the next generation']

#print the return_position as a line
print(''.join(str(return_position(textlist, search_for=['a', 'b']))))  # added explicit conversion to str

Your print was raising a type error as well because all elements of the iterable passed to str.join must be strings. It does not perform an explicit conversion like the print function.


EDIT: Please note that the algorithm, although it does not raise an error anymore, is missing one of your expected results because the algorithm is case sensitive. If you want it to be case insensitive use str.casefold or str.lower, see this answer. I would not use casefold to make sure that an "ß" is not replaced with a "ss", possibly turning the word into a different word with different pronounciation and different meaning like in the example in the linked answer (e.g. "busse" should not equal "buße").

jakun
  • 624
  • 5
  • 13