@@ -34,8 +34,10 @@ def add(array, key, value):
3434 Returns:
3535 Manipulated array
3636 """
37- if Arr .get (array , key ) is None :
38- Arr .set (array , key , value )
37+ if isinstance (array , list ) and isinstance (key , int ) and len (array ) < key :
38+ array .extend ([value ])
39+ elif Arr .get (array , key ) is None :
40+ array = Arr .set (array , key , value )
3941 return array
4042
4143 @staticmethod
@@ -50,14 +52,22 @@ def add_prefixed_keys_to(array, recursive=False):
5052 Returns:
5153 Manipulated array.
5254 """
53- if not isinstance (array , dict ):
55+ if not isinstance (array , dict ) and not isinstance ( array , list ) :
5456 return array
5557
58+ array = Arr .list_to_dict (array )
59+
5660 prefixed = {}
5761 for key , value in array .items ():
5862 if recursive and isinstance (value , dict ):
5963 value = Arr .add_prefixed_keys_to (value , True )
6064 array [key ] = {** array [key ], ** value }
65+ elif recursive and isinstance (value , list ):
66+ value = Arr .add_prefixed_keys_to (value , True )
67+ array [key ] = {** array [key ], ** value }
68+
69+ if isinstance (key , int ):
70+ key = str (key )
6171
6272 if not key .startswith ('_' ):
6373 prefixed [f'_{ key } ' ] = value
@@ -95,34 +105,6 @@ def add_unprefixed_keys_to(array, recursive=False):
95105 array .update (to_update )
96106 return array
97107
98- @staticmethod
99- def array_visit_recursive (input_array , visitor ):
100- """
101- Recursively visits all elements of an array applying the specified callback to each element key and value.
102-
103- Args:
104- input_array: The input array whose nodes should be visited.
105- visitor: A callback function that will be called on each array item; the callback will
106- receive the item key and value as input and should return an array that contains
107- the update key and value in the shape [ <key>, <value> ]. Returning a null
108- key will cause the element to be removed from the array.
109-
110- Returns:
111- Manipulated array.
112- """
113- if not isinstance (input_array , dict ):
114- return input_array
115-
116- result = {}
117- for key , value in input_array .items ():
118- if isinstance (value , dict ):
119- value = Arr .array_visit_recursive (value , visitor )
120- updated_key , updated_value = visitor (key , value )
121- if updated_key is not None :
122- result [updated_key ] = updated_value
123-
124- return result
125-
126108 @staticmethod
127109 def collapse (array ):
128110 """
@@ -214,7 +196,7 @@ def flatten(array, depth=float('inf')):
214196
215197 Args:
216198 array: Array to flatten.
217- depth (number , optional): Number of nestings deep that should be flattened. Defaults to float('inf').
199+ depth (int , optional): Number of nestings deep that should be flattened. Defaults to float('inf').
218200
219201 Returns:
220202 Flattened array.
@@ -285,40 +267,104 @@ def has(array, keys):
285267 return True
286268
287269 @staticmethod
288- def insert_after_key (key , source_array , insert ):
270+ def insert_after_key (key , source , insert ):
289271 """
290- Insert an array after a specified key within another array .
272+ Insert an item or items after a specified key within a list or a dictionary .
291273
292274 Args:
293- key (str|number ): The key of the array to insert after.
294- source_array (array ): The array to insert into.
275+ key (str|int ): The key or index of the item to insert after.
276+ source (list|dict ): The list or dictionary to insert into.
295277 insert (Any): Value or array to insert.
296278
297279 Returns:
298- Manipulated array .
280+ list|dict: Manipulated source with the insertions .
299281 """
300- if not isinstance (insert , list ):
301- insert = [insert ]
302- index = next ((i for i , k in enumerate (source_array ) if k == key ), len (source_array ))
303- return source_array [:index + 1 ] + insert + source_array [index + 1 :]
282+ if isinstance (source , list ):
283+ # Handle list
284+ if isinstance (key , int ) and 0 <= key < len (source ):
285+ insert_position = key + 1
286+ else :
287+ insert_position = len (source ) # Append at the end if out of bounds
288+ if isinstance (insert , list ):
289+ source [insert_position :insert_position ] = insert
290+ else :
291+ source .insert (insert_position , insert )
292+
293+ elif isinstance (source , dict ):
294+ # Handle dictionary
295+ if key in source :
296+ keys = list (source .keys ())
297+ index = keys .index (key ) + 1
298+ new_dict = {}
299+ for k in keys [:index ]:
300+ new_dict [k ] = source [k ]
301+ if isinstance (insert , dict ):
302+ new_dict .update (insert )
303+ else :
304+ # Raise error for non-dict inserts into dicts
305+ raise TypeError ("Insertion into a dictionary must be a dictionary" )
306+ for k in keys [index :]:
307+ new_dict [k ] = source [k ]
308+ source = new_dict
309+ else :
310+ if isinstance (insert , dict ):
311+ source .update (insert )
312+ else :
313+ source [key ] = insert # Add at the end if key does not exist
314+ else :
315+ raise TypeError ("Source must be either a list or a dictionary" )
316+
317+ return source
304318
305319 @staticmethod
306- def insert_before_key (key , source_array , insert ):
320+ def insert_before_key (key , source , insert ):
307321 """
308- Insert an array before a specified key within another array .
322+ Insert an item or items before a specified key within a list or a dictionary .
309323
310324 Args:
311- key (str|number ): The key of the array to insert before.
312- source_array (array ): The array to insert into.
325+ key (str|int ): The key or index of the item to insert before.
326+ source (list|dict ): The list or dictionary to insert into.
313327 insert (Any): Value or array to insert.
314328
315329 Returns:
316- Manipulated array .
330+ list|dict: Manipulated source with the insertions .
317331 """
318- if not isinstance (insert , list ):
319- insert = [insert ]
320- index = next ((i for i , k in enumerate (source_array ) if k == key ), len (source_array ))
321- return source_array [:index ] + insert + source_array [index :]
332+ if isinstance (source , list ):
333+ # Handle list
334+ if isinstance (key , int ) and 0 <= key < len (source ):
335+ insert_position = key
336+ else :
337+ # If the key is out of range, do not append it at the end; handle it as error or ignore
338+ raise IndexError ("List index out of range" )
339+ if isinstance (insert , list ):
340+ source [insert_position :insert_position ] = insert
341+ else :
342+ source .insert (insert_position , insert )
343+
344+ elif isinstance (source , dict ):
345+ # Handle dictionary
346+ if key in source :
347+ keys = list (source .keys ())
348+ index = keys .index (key )
349+ new_dict = {}
350+ for k in keys [:index ]:
351+ new_dict [k ] = source [k ]
352+ if isinstance (insert , dict ):
353+ new_dict .update (insert )
354+ else :
355+ # Raise error for non-dict inserts into dicts
356+ raise TypeError ("Insertion into a dictionary must be a dictionary" )
357+ for k in keys [index :]:
358+ new_dict [k ] = source [k ]
359+ source = new_dict
360+ else :
361+ # If the key does not exist, handle as error or ignore
362+ raise KeyError (f"Key '{ key } ' not found in dictionary" )
363+
364+ else :
365+ raise TypeError ("Source must be either a list or a dictionary" )
366+
367+ return source
322368
323369 @staticmethod
324370 def is_dict (array ):
@@ -392,25 +438,42 @@ def last(array, callback=None, default=None):
392438
393439 return default
394440
441+
395442 @staticmethod
396- def list_to_array (value , sep = ',' ):
443+ def list_to_dict (value ):
397444 """
398- Converts a list to an array filtering out empty string elements .
445+ Converts a list to a dict .
399446
400447 Args:
401- value (str|number|None): A string representing a list of values separated by the specified separator
402- or an array. If the list is a string (e.g. a CSV list) then it will urldecoded
403- before processing.
404- sep (str, optional): The char(s) separating the list elements; will be ignored if the list is an array. Defaults to ','.
448+ value (list): A list to convert to a dict.
405449
406450 Returns:
407- Manipulated array .
451+ dict: Converted list .
408452 """
409- if not value :
410- return []
411- if isinstance (value , str ):
412- value = value .split (sep )
413- return [v .strip () for v in value if v .strip ()]
453+ if isinstance (value , dict ):
454+ return value
455+
456+ value = Arr .wrap (value )
457+
458+ return dict (enumerate (value ))
459+
460+ @staticmethod
461+ def list_to_string (list_items , sep = ',' ):
462+ """
463+ Returns a list separated by the specified separator.
464+
465+ Args:
466+ list_items: Array of items.
467+ sep (str, optional): Separator. Defaults to ','.
468+
469+ Returns:
470+ The list separated by the specified separator or the original list if the list is empty.
471+ """
472+ if not list_items :
473+ return list_items
474+ if isinstance (list_items , list ):
475+ return sep .join (map (str , list_items ))
476+ return str (list_items )
414477
415478 @staticmethod
416479 def merge_recursive (array1 , array2 ):
@@ -454,7 +517,7 @@ def prepend(array, value, key=None):
454517 Args:
455518 array: Array to manipulate.
456519 value (Any): Value to prepend.
457- key (string|number , optional): Key value for the prepended item. Defaults to None.
520+ key (string|int , optional): Key value for the prepended item. Defaults to None.
458521
459522 Returns:
460523 Manipulated array.
@@ -475,7 +538,7 @@ def pull(array, key, default=None):
475538
476539 Args:
477540 array: Array to search and manipulate.
478- key (str|number ): Key to look for and fetch.
541+ key (str|int ): Key to look for and fetch.
479542 default (Any, optional): Default value if none found. Defaults to None.
480543
481544 Returns:
@@ -522,7 +585,7 @@ def random(array, number=None, preserve_keys=False):
522585
523586 Args:
524587 array: Array to search through.
525- number (number , optional): Number of items to randomly grab. Defaults to None.
588+ number (int , optional): Number of items to randomly grab. Defaults to None.
526589 preserve_keys (bool, optional): Whether the keys should be preserved or not. Defaults to False.
527590
528591 Raises:
@@ -713,22 +776,24 @@ def strpos(haystack, needles, offset=0):
713776 return min_position if min_position != len (haystack ) else False
714777
715778 @staticmethod
716- def to_list ( list_items , sep = ',' ):
779+ def str_to_list ( value , sep = ',' ):
717780 """
718- Returns a list separated by the specified separator .
781+ Converts a list to an array filtering out empty string elements .
719782
720783 Args:
721- list_items: Array of items.
722- sep (str, optional): Separator. Defaults to ','.
784+ value (str|int|None): A string representing a list of values separated by the specified separator
785+ or an array. If the list is a string (e.g. a CSV list) then it will urldecoded
786+ before processing.
787+ sep (str, optional): The char(s) separating the list elements; will be ignored if the list is an array. Defaults to ','.
723788
724789 Returns:
725- The list separated by the specified separator or the original list if the list is empty .
790+ Manipulated array .
726791 """
727- if not list_items :
728- return list_items
729- if isinstance (list_items , list ):
730- return sep . join ( map ( str , list_items ) )
731- return str ( list_items )
792+ if not value :
793+ return []
794+ if isinstance (value , str ):
795+ value = value . split ( sep )
796+ return [ v . strip () for v in value if v . strip ()]
732797
733798 @staticmethod
734799 def undot (obj ):
@@ -781,6 +846,34 @@ def usearch(needle, haystack, callback):
781846 return key
782847 return False
783848
849+ @staticmethod
850+ def visit_recursive (input_array , visitor ):
851+ """
852+ Recursively visits all elements of an array applying the specified callback to each element key and value.
853+
854+ Args:
855+ input_array: The input array whose nodes should be visited.
856+ visitor: A callback function that will be called on each array item; the callback will
857+ receive the item key and value as input and should return an array that contains
858+ the update key and value in the shape [ <key>, <value> ]. Returning a null
859+ key will cause the element to be removed from the array.
860+
861+ Returns:
862+ Manipulated array.
863+ """
864+ if not isinstance (input_array , dict ):
865+ return input_array
866+
867+ result = {}
868+ for key , value in input_array .items ():
869+ if isinstance (value , dict ):
870+ value = Arr .visit_recursive (value , visitor )
871+ updated_key , updated_value = visitor (key , value )
872+ if updated_key is not None :
873+ result [updated_key ] = updated_value
874+
875+ return result
876+
784877 @staticmethod
785878 def where (array , callback ):
786879 """
0 commit comments