1

need to make a csv file.(not as important, but due to the large size, i thought this would be for the best.)

in the first column there is value of [3,3,3] all the way until [-3,-3,-3] in the second column. it is the same as first column, [3,3,3] to [-3,-3,-3].

so how it works is that for every unqiue occrance of the first column, the value of second column will go through [3,3,3] to [-3,-3,-3]

for example.

[3,3,3], [3,3,3]
[3,3,3], [3,3,2]
[3,3,3], [3,3,1]
[3,3,3], [3,3,-1]
[3,3,3], [3,3,-2]
[3,3,3], [3,3,-3]
[3,3,3], [3,2,2]
[3,3,3], [3,2,1]
[3,3,3], [3,2,-1]
...
[3,3,3], [3,2,-3]
...
[3,3,2],[3,3,3] # since the first column changed, it will repeat [3,3,3] to [-3,-3,-3] in the second column
...
[3,3,2] [-3,-3,-3]

there can't be repeats in both columns. this is considered a repeat [3,1,3] and [3,3,1] where in both occurnace 3 shows up twice and 1 shows up once. there also can't be 0 in either columns. meaning once you are counting down from 3 to -3, it will go from 1, to -1.

so far my code looks like.

first_column = [3, 3, 3]
second_column = [3, 3, 3]

while second_column != [-3, -3, -3]:
    print([first_column, second_column])
    second_column[2] -= 1
    if second_column[2] < -3:
        second_column[2] = 3
        second_column[1] -= 1
        if second_column[1] < -3:
            second_column[1] = 3
            second_column[0] -= 1

this only do [3,3,3] first column. and it was repeating values and 0. it will be greatly appreciated if someone can appoint me to the right path, and also make the code look prettier.

please no chatgpt answers......it doesnt work there.

edit: overall this should make around 450,000 rows.

Tim
  • 95
  • 7
  • 1
    Just to make sure I understand correctly, the total number of lines in this csv file is supposed to be roughly 649000? – Alexander Feb 20 '23 at 07:07
  • Also if there can't be repeats in both columns then why are both columns in row 1 identical? [3,3,3], [3,3,3] ? – Alexander Feb 20 '23 at 07:13
  • yes the total number would be 649000, the two columns can have identicals, for example. column1: [3,3,3], column2: [3,3,3] , or c1:[2,2,2], c2:[2,2,2]. however the columns themselves cant have identicals. like column1: [3,1,3] and column1: [3,3,1] – Tim Feb 20 '23 at 07:17
  • I still do not understand the repeats in the same column part... the first column has countless repeats in it one right after another – Alexander Feb 20 '23 at 07:21
  • one row is like this [[3, 3, 3], [3, 1, 3]], another row is like this [[3, 3, 3], [3, 3, 1]], notice how in the second row there are 2 threes and one, 1. thats considered a repeat. – Tim Feb 20 '23 at 07:21

3 Answers3

0

I still am not sure that I fully understand the instructions, and this example is certainly not the most efficient approach, however it is the most concise way that I could think of.

from pathlib import Path
from collections import Counter
from itertools import combinations
contents = ""
full = lambda: sorted(list(combinations([1,2,3,-1,-2,-3]*3, 3)), reverse=True)
for row1 in full():
    for row2 in full():
        if Counter(row1) != Counter(row2):
            contents += str(list(row1)) + "," + str(list(row2)) + "\n"
Path('file.csv').write_text(contents, encoding="utf8")

The output file has exactly 648840 rows and took about 6 seconds on my machine. There are more than a few obvious performance improvements that can be made.


Edit

Based on your further explanation of what a repeat is, this might actually be what you are looking for, except this method only produces about 45000 lines.

full = lambda: sorted(list(combinations([1,2,3,-1,-2,-3]*3, 3)), reverse=True)
for row1 in full():
    arrangements = []
    for row2 in full():
        counter = Counter(row2)
        if counter not in arrangements:
            contents += str(list(row1)) + "," + str(list(row2)) + "\n"
            arrangements.append(counter)
Path('file.csv').write_text(contents, encoding="utf8")

Either way, if your goal is to do this efficiently, then neither of these solutions is a good way to go.


This minor tweak makes it significantly more memory efficient.

from collections import Counter
from itertools import combinations
import csv
writer = csv.writer(open('file.csv', 'wt'), quoting=csv.QUOTE_NONE, escapechar='.')
full = lambda: sorted(list(combinations([1,2,3,-1,-2,-3]*3, 3)), reverse=True)
for row1 in full():
    arrangements = []
    for row2 in full():
        counter = Counter(row2)
        if counter not in arrangements:
            writer.writerow([list(row1) , list(row2)])
Alexander
  • 16,091
  • 5
  • 13
  • 29
0

I don't like @Alexander's version, because generating all the permutations and sorting them in-memory is obviously inefficient, when all we should do is essentially decrement one number in a list at a time. So here's my half-baked approach:

lim = 3
length = 6


def dec_list(line_list, i=-1):
    if i < -length:
        return False
    if line_list[i] > -lim:
        d = line_list[i]
        line_list[i] = (d - 1) or (d - 2)
        return line_list
    line_list[i] = lim
    return dec_list(line_list, i-1)


line_list = [lim] * length

while True:
    print(f"{line_list[:length//2]}, {line_list[length//2:]}")
    line_list = dec_list(line_list)
    if not line_list:
        break

Numbers are stored within one list, and we start with list of six threes. Then we decrement the last digit that we can, and shift left when trying to decrement -3.

Nikolaj Š.
  • 1,457
  • 1
  • 10
  • 17
0

The task looks suspiciously similar to printing all the numbers for a given range, so here's another approach (with numberToBase() stolen from "How to convert an integer to a string in any base?" =)

lim = 3
length = 6

base = lim * 2


def numberToBase(n, b):
    if n == 0:
        return [0]
    digits = []
    while n:
        digits.append(int(n % b))
        n //= b
    return digits[::-1]


def transform_int(digit):
    """
    [0..5] -> [-3, -2, -1, 1, 2, 3]
    (for any `lim` and `length`)
    """
    num = digit - lim + 1
    return num if num > 0 else num - 1


for i in range(base ** length - 1, -1, -1):
    # convert number to list of digits
    num_list = numberToBase(i, base)
    # pad with zeroes
    num_list = [0] * (base - len(num_list)) + num_list
    # mangle digits
    num_list = [transform_int(j) for j in num_list]
    print(f"{num_list[:length//2]}, {num_list[length//2:]}")
Nikolaj Š.
  • 1,457
  • 1
  • 10
  • 17