Форум русскоязычного сообщества Ubuntu


Получить помощь и пообщаться с другими пользователями Ubuntu можно
на irc канале #ubuntu-ru в сети Freenode
и в Jabber конференции ubuntu@conference.jabber.ru

Автор Тема: Задачка для тренировки  (Прочитано 6418 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн obgorelyi

  • Автор темы
  • Новичок
  • *
  • Сообщений: 45
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #15 : 11 Июня 2013, 23:45:26 »
За один цикл массив создаю, за второй цикл печатаю.
N = 5

counter = 1
array = [[1]]
L = 2

# Индекс строки
i = 0
while counter<(2*N-1)**2:
  counter +=1
 
  # Налево сказку говорим
  # Если длинна array - нечетная
  if counter<=L:
    array[i].insert(0,counter)
    up = len(array)
  # Идем вверх
  elif(counter<=L+up):
    i-=1
    if i<0:
      array.insert(0,[counter])
      R = len(array)**2+1
      i+=1
    else:
      array[i].insert(0,counter)
   
  elif(counter<=R):
    array[0].append(counter)
    down = len(array)
  elif(counter<=R+down):
    i+=1
    if i>=down:
      array.append([counter])
      L = len(array)**2+1
    else:
      array[i].append(counter)
   
for iterat in array:
  print(iterat)

Честно сказать идея осталась та же, что и в первой программе. Количество проходов в циклах 77(из-за того, что переход на следующее кольцо и шаг вверх в одной итерации идут), 92, 81 в первой, второй и третьей программах соответственно, то есть самая плохая, если считать критерием юродивости, количество вхождений в цикл, это вторая программа. Интересно, какие критерии оптимальности используют при программировании. Может кто скажет?

Также возник вопрос, на C++, С, Pascal можно создать пустой двумерный массив:
int arr[N][N];

А на Python'е, как реализовать подобное?
Попробовал в режиме интерпретатора, получил "чудеса", когда попытался по индексам присвоить :)
>>> a=[[[]]*5]*5
>>> a
[[[], [], [], [], []], [[], [], [], [], []], [[], [], [], [], []], [[], [], [], [], []], [[], [], [], [], []]]
>>> a[3][1]=10
>>> a
[[[], 10, [], [], []], [[], 10, [], [], []], [[], 10, [], [], []], [[], 10, [], [], []], [[], 10, [], [], []]]

>>> a=[[0]*5]*5
>>> a[3][1]=10
>>> a
[[0, 10, 0, 0, 0], [0, 10, 0, 0, 0], [0, 10, 0, 0, 0], [0, 10, 0, 0, 0], [0, 10, 0, 0, 0]]


to inkblack: Ясный и обслуживаемый код? Если не секрет, что вы под этим подразумеваете? Просто у каждого свои понятия на этот счет.

Оффлайн Phlya

  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #16 : 12 Июня 2013, 00:00:39 »
В питоне можно либо использовать список списков, что тут у Вас и получилось, либо использовать NumPy, где определен класс array с произвольной размерностью.
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн inkblack

  • Старожил
  • *
  • Сообщений: 1216
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #17 : 12 Июня 2013, 00:14:11 »
... Ясный и обслуживаемый код? Если не секрет, что вы под этим подразумеваете? Просто у каждого свои понятия на этот счет.

Ну, насчет ясного — действительно, это каждый по-своему понимает.
А обслуживаемый — тот, в котором вы после годового перерыва сможете
что-нибудь поменять по делу.
Делюсь знаниями, но их у меня мало!

Оффлайн obgorelyi

  • Автор темы
  • Новичок
  • *
  • Сообщений: 45
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #18 : 12 Июня 2013, 08:40:31 »
to Plya: Список списков сделать, то я сделал, только ты на результат присвоения посмотри :). Он проигнорировал, то что я хочу поставить число 10 в 3-й строке, 1-м столбце, он мне поставил число во все строки, хорошо, хоть по номеру столбца :). Просто сталкивался с этой фичей. И вот интересно, как тогда присвоение делать, или массив объявлять? Желательно без NumPy меня пока интересует голый Python. Просто Numpy насколько знаю для серьезных вычислений, а для этих целей я пользуюсь Octave, ну и с недавних пор Maxima.

Кстати, кто как ищет ошибки в программе?

Оффлайн Phlya

  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #19 : 12 Июня 2013, 11:27:18 »
Да, с проставлением во все вложенные списки я сталкивался, но почему это происходит не было времени разобраться.
Двумерный массив на голом питоне сделать нельзя.
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн Jack Sparrow

  • Активист
  • *
  • Сообщений: 630
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #20 : 12 Июня 2013, 17:26:07 »
Можно создать свой тип данных. Например, так:
Код: (Python) [Выделить]
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 2D Матрица, эмуляция двухразмерного массива

class Matrix:
    """2D матрица."""
    def __init__(self, x = 3, y = 3):
        # Параметры x и y задают размер матрицы по умолчанию
        self.matrix = [[0 for row in range(x)] for col in range(y)]
   
    def __str__(self):
        # Выводит содержание матрицы в строковом виде, если применить функцию print()
        res = []
        for row in self.matrix:
            res.append(str(row))
       
        # Возвращаем результат, удаляя квадратные скобки
        return '\n'.join(res).replace('[','').replace(']','')
   

# Создаем матрицу размером 4x8. По умолчанию было бы 3x3.
t = Matrix(4,8)

# Присваиваем 5 ячейке [строка][колонка]
t.matrix[1][2] = 5
print(t)
Конечно, не все тут логично. Например, при создании объекта Matrix(x, y) x это колонки, а у это строки (по Декарту). А при присвоении "t.matrix[у][х]" все наоборот: сначала идет строка, а потом колонка.

PS. Кстати, какой-то движок странный у форума. Попробуйте набрать t.matrix[у][х] и сделать предпросмотр. Только х должен быть латинский (у меня там русский).
Linux is only free if your time has no value (c) Jamie Zawinski

Оффлайн Phlya

  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #21 : 12 Июня 2013, 17:34:42 »
Проще использовать numpy, ИМХО.
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн obgorelyi

  • Автор темы
  • Новичок
  • *
  • Сообщений: 45
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #22 : 12 Июня 2013, 19:40:47 »
to Jack Sparrow: Забавную ты штуку нашел, с помощью нее самое-то маркированные списки составлять :).
  • Во-первых: спасибо за class.
  • Во-вторых: увидев твою программу, я понял, что зря не полностью прочитал учебник по Python'у. (Правда если честно уже две недели по несколько страниц читаю и практикуюсь).
  • В-третьих: Матрица не пустая :(, там нули, а я хотел [], ну раз там нуль, значит с нулем и будем прыгать :).

Спасибо вам, за практичный пример. ;)

to Phlya: NumPy вроде прикольная вещь, но меня пока интересует голый Python исключительно из личных соображений :).

Оффлайн Phlya

  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #23 : 12 Июня 2013, 19:42:57 »
numpy очень мощная вещь, сильно ускоряет большие вычисления и позволяет проводить многие операции значительно проще. Но как Вам угодно, разумеется, можно и велосипед заново изобрести =)
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн Jack Sparrow

  • Активист
  • *
  • Сообщений: 630
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #24 : 12 Июня 2013, 22:58:16 »
В-третьих: Матрица не пустая :( , там нули, а я хотел [], ну раз там нуль, значит с нулем и будем прыгать :) .
Я хотел ввести третий параметр, но подумал, что лучше не усложнять для объяснения. Хотя это делается элементарно. Там за заполнение отвечает 0 в цикле. Просто изменим немного метод __init__:
Код: (Python) [Выделить]
def __init__(self, x = 3, y = 3, default = ''):
        # Параметры x и y задают размер матрицы по умолчанию
        self.matrix = [[default for row in range(x)] for col in range(y)]
Теперь если использовать конструктор так:
Код: (Python) [Выделить]
t = Matrix(4,8)то по умолчанию вместо нулей будет ''. А если нужны нули, то нужно создавать так:
Код: (Python) [Выделить]
t = Matrix(4, 8, 0)Ну или что-то другое вместо нуля.

Phlya, совершенно верно, в общих случаях лучше использовать готовые и проверенные решения. Но в учебных целях можно и велосипед поизобретать. Или если импортируемый модуль слишком тяжелый, а нужны лишь копеечные возможности, то тоже можно свой класс создать. Опять же, иногда проще создать свой небольшой класс, чем разобраться в готовом, особенно, если он очень мощный. Короче, тут очень много нюансов и разных подходов.
Linux is only free if your time has no value (c) Jamie Zawinski

Оффлайн Phlya

  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #25 : 12 Июня 2013, 23:15:53 »
Да, разумеется, я это понимаю, но,все-таки, как мне кажется, полезнее разобраться с numpy, чем городить собственные решения. А тяжесть модуля ну никак не заметна нигде. Но на вкус и цвет, как говориться...
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн Jack Sparrow

  • Активист
  • *
  • Сообщений: 630
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #26 : 12 Июня 2013, 23:56:29 »
Да, разумеется, я это понимаю, но,все-таки, как мне кажется, полезнее разобраться с numpy, чем городить собственные решения.
Хоть в свете этого я уже и начинаю ощущать комплекс вины :( , но, тем не менее, вот доработанный велосипед:
Код: (Python) [Выделить]
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 2D Матрица, эмуляция двухразмерного массива

class Matrix:
    """2D матрица."""
    def __init__(self, x = 3, y = 3, default = ''):
        # Параметры x и y задают размер матрицы по умолчанию
        self._matrix = [[default for row in range(x)] for col in range(y)]
   
    def __str__(self):
        # Выводит содержание матрицы в строковом виде.
        res = []
        for row in self._matrix:
            res.append(str(row))
       
        # Возвращаем результат, удаляя квадратные скобки
        return '\n'.join(res).replace('[','').replace(']','')
   
    def get(self, x, y):
        # Получить значение ячейки
        return self._matrix[y][x]
   
    def set(self, x, y, value):
        # Установить значение ячейки
        self._matrix[y][x] = value
   

# Создаем матрицу размером 4x8. По умолчанию было бы 3x3.
t = Matrix(4,8, 0)

# Присваиваем 5 ячейке [строка][колонка]. Старый синтаксис
# Метод, начинающийся с одиночного символа подчеркивания предназначен для внутреннего использования.
# Но это, тем не менее, лишь соглашение, а не требование. Он все равно доступен. Если же нужно, чтобы он
# в принципе не был доступен, то его нужно определять в классе с двойным начальным подчеркиванием: __matrix
# Но вики утверждает, что последнее используется редко (хотя не знаю, почему), вот и я не стал.
t._matrix[1][2] = 5

# Этот метод уже работает по-декартовски: 3 это х, а 2 это у.
# Если это не нравится, то в методе set можно поменять местами х и у в одном месте.
# Можно не только числа, но и что угодно вносить в матрицу, все, что позволяет список.
t.set(3,2,'hello')
print(t)

# А это мы получаем значение конкретной ячейки, тоже, кстати, декартовской. Опять же,
# можно поменять местами х и у в методе get, если не наравится.
print(t.get(2,1))
Добавил два метода get и set для чтения и установки значений. Теперь через эти методы координация определяется уже последовательно, т.е. на первом месте и идет координата x, а на втором - y, как и в конструкторе.
Linux is only free if your time has no value (c) Jamie Zawinski

Оффлайн Phlya

  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #27 : 13 Июня 2013, 00:05:27 »
В принципе, может быть и полезно сделать такой класс, как у Вас получается, если его хорошо развить. А дальше просто копировать файлик в каталог проекта и импортировать. В общем, буду с интересом следить за развитием событий =)
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн Jack Sparrow

  • Активист
  • *
  • Сообщений: 630
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #28 : 13 Июня 2013, 00:45:18 »
Из своего любительского опыта знаю, что иногда находишь "правильное" решение, т.е. специальный модуль или библиотеку, но они бывают настолько сложны, что кажется, что проще что-то самому создать, чем разобраться с ними. Например, хотел как-то разобраться с поддержкой utf-8 в C/C++. На stackoverflow было сказано, что можно делать как-то по-простому, через w_char или что-то в этом роде. Потом один говорит, что для простых случаев это подходит, но, тем не менее, иногда будут ошибки, например, немецкая ß неправильно делается, если хочешь получить ее заглавной. Но есть-де какая-то там библиотека, которая все корректно делает. Но на том же stackoverflow люди жаловались, что эта библиотека не для средних умов.

А по поводу создания собственных классов, так это больше для удовольствия. Мы ведь здесь (по крайней мере в этой теме) не то чтобы ищем готовое решение, а больше для изучения.

Или вот, например, понадобится мне тип данных, чтобы составлять или решать кроссворды. Так можно будет этот класс доработать. Например, добавить метод, скажем, insert, который будет вставлять слово в кроссворд. Скажем, синтаксис будет такой:
t.insert(x, y, word, direction)
По х и у задается начальная ячейка. word это, понятно, слово, которое нужно вставить. А  это будет задавать направление: 'up', 'down', 'left', 'right'.  Если слово вставить нельзя, например, выходит за границы или пересекает другое слово, а буква при пересечении не совпадает, то будет выдавать соответствующий код.

Или, скажем, есть такие кроссворды-матрицы, где нужно отыскать слова в них и вычеркнуть. Тоже можно приспособить этот класс. И т.п. Все это больше для развлечения и обучения. А обучаться лучше на интересных примерах. Мне, например, если бы читать примеры из бухгалтерии с дебитами, кредитами, сальдо и процентами (как вспомню программистов с бывшей работы, работавших с 1С, так вздрогну), то я бы, скорее всего, ничего бы не освоил. Кстати, поэтому мне и нравится книга Think Python.
Linux is only free if your time has no value (c) Jamie Zawinski

Оффлайн obgorelyi

  • Автор темы
  • Новичок
  • *
  • Сообщений: 45
    • Просмотр профиля
Re: Задачка для тренировки
« Ответ #29 : 13 Июня 2013, 21:23:37 »
Во всем можно разобраться, только вот есть такие, аспекты, по которым разобраться сложно! Например в этой библиотеки NumPy, есть своя добрая куча проблем (как и везде). Побаловался с ней, (уж больно меня Phlya заинтриговал). В результате узнал, что у нее следующие недостатки.
  • В матрицу нельзя засунуть переменные, матерится.
>>> from numpy import *
>>> a=matrix('10,5;6,7')
>>> a
matrix([[10,  5],
        [ 6,  7]])
>>> b = 10
>>> b
10
>>> a=matrix('b,5;6,7')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.3/site-packages/numpy/matrixlib/defmatrix.py", line 254, in __new__
    data = _convert_from_string(data)
  File "/usr/lib64/python3.3/site-packages/numpy/matrixlib/defmatrix.py", line 46, in _convert_from_string
    newrow.extend(list(map(_eval,temp)))
  File "/usr/lib64/python3.3/site-packages/numpy/matrixlib/defmatrix.py", line 20, in _eval
    return eval(astr.translate(_table))
  File "<string>", line 0
   
    ^
SyntaxError: unexpected EOF while parsing
  • Единственный способ, который я нашел, как туда сунуть переменные, это создать массив, а потом сделать из него матрицу!
>>> a=array([(b,5),(6,7)])
>>> a
array([[10,  5],
       [ 6,  7]])
>>> a = matrix(a)
>>> a
matrix([[10,  5],
        [ 6,  7]])
  • Далее при таком преобразовании, вектор столбец она мне в строку преобразует!
>>> f = array([(10),(15)])
>>> f
array([10, 15])
>>> f = matrix(f)
>>> f
matrix([[10, 15]])
  • Слава богу от этого избавиться можно.
>>> f = array([(10,),(15,)])
>>> f
array([[10],
       [15]])
>>> f = matrix(f)
>>> f
matrix([[10],
        [15]])
  • Потом при создании матрицы массива и т.д. это все счастье записывается в одну строчку! Не знаю, как вам мне плохо станет, вводить (если брать пример из рабочей практики), матрицу 8x8 в одну строку, при том, что в ячейке может находиться формула длинной со строку!
  • Ну и теперь о крупных нюансах, решил провести решение обычной СЛАУ.

Сначала рассмотрим простенький примерчик (Ввод матриц, я убрал, чтобы глаза не мозолил):
>>> a
matrix([[10,  5],
        [ 6,  7]])
>>> f
matrix([[10],
        [15]])
>>> a.I*f
matrix([[-0.125],
        [ 2.25 ]])
>>> X = a.I*f
>>> a*X
matrix([[ 10.],
        [ 15.]])
Все верно :).
Возьмем примерчик посложнее.
>>> a
matrix([[  1,   2,   3,   4,   5,   6,   7,   8],
        [  8,   3,   5,   6,   9,  13,  19,  47],
        [ 10,  20,  30,  40,  50,  60,  70,  80],
        [ 11,  12,  13,  14,  15,  16,  17,  18],
        [ 21,  22,  23,  24,  25,  26,  27,  28],
        [ 31,  32,  43,  54,  65,  26,  47,  68],
        [ 11, 223,  43,  54,  65,  36,  87,  28],
        [ 31,  52,  73,   4,  95,  66,  47,  38]])
>>> f
matrix([[12],
        [13],
        [24],
        [56],
        [68],
        [36],
        [96],
        [45]])
>>> X = a.I*f
>>> X
matrix([[  2.84378223e+15],
        [  3.72400812e+15],
        [ -2.18442758e+16],
        [  5.29098869e+15],
        [  1.21532679e+16],
        [  1.35353493e+16],
        [ -1.77236028e+16],
        [  2.02048222e+15]])
>>> a*X
matrix([[  16.],
        [   0.],
        [ 160.],
        [ -16.],
        [  88.],
        [-416.],
        [-296.],
        [ -32.]])

Результат-то не сходится!
Вычислял в обоих случаях, одинаково.
Решил проверить, что если в GNU Octave решить таким же способом, там я получил сообщение об ошибке, и столь же кривой результат :).
Тогда решил проверить решатели (или солверы, как их еще называют):
В Octave это операция A\F. Вот результат.
X1 =

   3.17254
   0.52287
   0.54927
   0.57066
  -2.15844
   1.59872
  -0.19017
  -0.38007

ans =

    2.5771
   13.0000
   25.7708
   39.4308
   76.2846
   36.0000
   96.0000
   45.0000
Тоже не идеал, 4 ответа не совпадает, теперь посмотрим NumPy.
В NumPy это linalg.solve(a,f).
>>> X
matrix([[  2.84378223e+15],
        [  3.72400812e+15],
        [ -2.18442758e+16],
        [  5.29098869e+15],
        [  1.21532679e+16],
        [  1.35353493e+16],
        [ -1.77236028e+16],
        [  2.02048222e+15]])
>>> a*X
matrix([[  24.],
        [  48.],
        [ 128.],
        [ 104.],
        [ 240.],
        [ -80.],
        [ -16.],
        [ 128.]])
Результат был для меня неожиданным, честно сказать, я надеялся, что результат будет аналогичен, но увы.
Поэтому для баловства можно и с NumPy попрыгать, для серьезных работ, лучше Octave, а еще лучше, что-нибудь посерьезнее Octave.
Еще мне вспомнилось, что есть пакет Gap, его тоже хочу протестировать на данной простой системке, но увы у меня жутко медленный инет, по этому скорее всего до утра таки скачаю Gap.
Надеюсь я не обидел чувств верующих :) А то за это и посадить теперь могут на 3 года :).
« Последнее редактирование: 14 Июня 2013, 19:28:59 от obgorelyi »

 

Страница сгенерирована за 0.053 секунд. Запросов: 25.