Skip to content

Commit

Permalink
Multi-dimensional array added (#256)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeanPierreMR authored May 15, 2020
1 parent 2284b55 commit 5f5e386
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 10 deletions.
3 changes: 2 additions & 1 deletion pydatastructs/linear_data_structures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

from .arrays import (
OneDimensionalArray,
DynamicOneDimensionalArray
DynamicOneDimensionalArray,
MultiDimensionalArray
)
__all__.extend(arrays.__all__)

Expand Down
131 changes: 124 additions & 7 deletions pydatastructs/linear_data_structures/arrays.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
from pydatastructs.utils.misc_util import _check_type, NoneType

__all__ = [
'OneDimensionalArray',
'DynamicOneDimensionalArray'
'OneDimensionalArray',
'MultiDimensionalArray',
'DynamicOneDimensionalArray'
]

class Array(object):
'''
Abstract class for arrays in pydatastructs.
'''
pass
def __str__(self) -> str:
return str(self._data)

class OneDimensionalArray(Array):
'''
Expand Down Expand Up @@ -112,8 +114,7 @@ def __new__(cls, dtype=NoneType, *args, **kwargs):
@classmethod
def methods(cls):
return ['__new__', '__getitem__',
'__setitem__', 'fill', '__len__',
'__str__']
'__setitem__', 'fill', '__len__']

def __getitem__(self, i):
if i >= self._size or i < 0:
Expand All @@ -136,9 +137,125 @@ def fill(self, elem):
def __len__(self):
return self._size

def __str__(self):
return str(self._data)
class MultiDimensionalArray(Array):
"""
Represents a multi-dimensional array.
Parameters
==========
dtype: type
A valid object type.
*args: int
The dimensions of the array.
Raises
======
IndexError
Index goes out of boundaries, or
the number of index given is not
the same as the number of dimensions.
ValueError
When there's no dimensions or the
dimension size is 0.
Examples
========
>>> from pydatastructs import MultiDimensionalArray as MDA
>>> arr = MDA(int, 5, 6, 9)
>>> arr.fill(32)
>>> arr[3, 0, 0]
32
>>> arr[3, 0, 0] = 7
>>> arr[3, 0, 0]
7
References
==========
.. [1] https://en.wikipedia.org/wiki/Array_data_structure#Multidimensional_arrays
"""
__slots__ = ['_sizes', '_data', '_dtype']

def __new__(cls, dtype: type = NoneType, *args, **kwargs):
if dtype is NoneType or not args:
raise ValueError("Array cannot be created due to incorrect"
" information.")
if len(args) == 1:
obj = Array.__new__(cls)
obj._dtype = dtype
obj._sizes = (args[0], 1)
obj._data = [None] * args[0]
return obj

dimensions = args
for dimension in dimensions:
if dimension < 1:
raise ValueError("Array cannot be created due to incorrect"
" dimensions.")
n_dimensions = len(dimensions)
d_sizes = []
index = 0
while n_dimensions > 1:
size = dimensions[index]
for i in range(index+1, len(dimensions)):
size = size * dimensions[i]
d_sizes.append(size)
n_dimensions -= 1
index += 1
d_sizes.append(dimensions[index])
d_sizes.append(1)
obj = Array.__new__(cls)
obj._dtype = dtype
obj._sizes = tuple(d_sizes)
obj._data = [None] * obj._sizes[1] * dimensions[0]
return obj

@classmethod
def methods(cls) -> list:
return ['__new__', '__getitem__', '__setitem__', 'fill', 'shape']

def __getitem__(self, indices):
self._compare_shape(indices)
if isinstance(indices, int):
return self._data[indices]
position = 0
for i in range(0, len(indices)):
position += self._sizes[i + 1] * indices[i]
return self._data[position]

def __setitem__(self, indices, element) -> None:
self._compare_shape(indices)
if isinstance(indices, int):
self._data[indices] = element
else:
position = 0
for i in range(0, len(indices)):
position += self._sizes[i + 1] * indices[i]
self._data[position] = element

def _compare_shape(self, indices) -> None:
indices = [indices] if isinstance(indices, int) else indices
if len(indices) != len(self._sizes) - 1:
raise IndexError("Shape mismatch, current shape is %s" % str(self.shape))
if any(indices[i] >= self._sizes[i] for i in range(len(indices))):
raise IndexError("Index out of range.")

def fill(self, element) -> None:
element = self._dtype(element)
for i in range(len(self._data)):
self._data[i] = element

@property
def shape(self) -> tuple:
shape = []
size = len(self._sizes)
for i in range(1, size):
shape.append(self._sizes[i-1]//self._sizes[i])
return tuple(shape)

class DynamicArray(Array):
"""
Expand Down
35 changes: 34 additions & 1 deletion pydatastructs/linear_data_structures/tests/test_arrays.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pydatastructs.linear_data_structures import (
OneDimensionalArray, DynamicOneDimensionalArray)
OneDimensionalArray, DynamicOneDimensionalArray, MultiDimensionalArray)
from pydatastructs.utils.raises_util import raises


Expand All @@ -21,6 +21,39 @@ def test_OneDimensionalArray():
assert raises(TypeError, lambda: ODA(int, set([1, 2, 3])))
assert raises(ValueError, lambda: ODA(int, 3, [1]))


def test_MultiDimensionalArray():
assert raises(ValueError, lambda: MultiDimensionalArray(int, 2, -1, 3))
assert MultiDimensionalArray(int, 10).shape == (10,)
array = MultiDimensionalArray(int, 5, 9, 3, 8)
assert array.shape == (5, 9, 3, 8)
array.fill(5)
array[1, 3, 2, 5] = 2.0
assert array
assert array[1, 3, 2, 5] == 2.0
assert array[1, 3, 0, 5] == 5
assert array[1, 2, 2, 5] == 5
assert array[2, 3, 2, 5] == 5
assert raises(IndexError, lambda: array[5])
assert raises(IndexError, lambda: array[4, 10])
assert raises(IndexError, lambda: array[-1])
assert raises(IndexError, lambda: array[2, 3, 2, 8])
assert raises(ValueError, lambda: MultiDimensionalArray())
assert raises(ValueError, lambda: MultiDimensionalArray(int))
assert raises(TypeError, lambda: MultiDimensionalArray(int, 5, 6, ""))
array = MultiDimensionalArray(int, 3, 2, 2)
array.fill(1)
array[0, 0, 0] = 0
array[0, 0, 1] = 0
array[1, 0, 0] = 0
array[2, 1, 1] = 0
assert str(array) == '[0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0]'
array = MultiDimensionalArray(int, 4)
assert array.shape == (4,)
array.fill(5)
array[3] = 3
assert array[3] == 3

def test_DynamicOneDimensionalArray():
DODA = DynamicOneDimensionalArray
A = DODA(int, 0)
Expand Down
2 changes: 1 addition & 1 deletion pydatastructs/utils/tests/test_code_quality.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def _apis():
pyds.DoublyLinkedList, pyds.SinglyLinkedList,
pyds.SinglyCircularLinkedList,
pyds.DoublyCircularLinkedList,
pyds.OneDimensionalArray,
pyds.OneDimensionalArray, pyds.MultiDimensionalArray,
pyds.DynamicOneDimensionalArray,
pyds.trees.BinaryTree, pyds.BinarySearchTree,
pyds.AVLTree, pyds.SplayTree, pyds.BinaryTreeTraversal,
Expand Down

0 comments on commit 5f5e386

Please sign in to comment.