#!/usr/bin/env python3 # Python utils # dennis(a)yurichev.com, 2017-2022 from typing import List from typing import Any import math, os def read_lines_from_file (fname): f=open(fname) new_ar=[item.rstrip() for item in f.readlines()] f.close() return new_ar # reverse list: def rvr(i:List[Any]) -> List[Any]: return i[::-1] def reflect_vertically(a:List[List[Any]]) -> List[List[Any]]: return [rvr(row) for row in a] def reflect_horizontally(a:List[List[Any]]) -> List[List[Any]]: return rvr(a) # N.B. must work on arrays of arrays of objects, not on arrays of strings! def rotate_rect_array_90_CCW(a_in:List[List[Any]]) -> List[List[Any]]: a=reflect_vertically(a_in) rt=[] # reflect diagonally: for row in range(len(a[0])): #rt.append("".join([a[col][row] for col in range(len(a))])) rt.append([a[col][row] for col in range(len(a))]) return rt # angle: 0 - leave as is; 1 - 90 CCW; 2 - 180 CCW; 3 - 270 CCW # FIXME: slow def rotate_rect_array(a:List[List[Any]], angle:int) -> List[List[Any]]: if angle==0: return a assert (angle>=1) assert (angle<=3) for i in range(angle): a=rotate_rect_array_90_CCW(a) return a # yet unused # TODO: test rectangles def rotate_rect_array_test(): rnd=[[1,2,3],[4,5,6],[7,8,9]] rotate_rect_array(rnd, 1)==[[3, 6, 9], [2, 5, 8], [1, 4, 7]] rotate_rect_array(rnd, 2)==[[9, 8, 7], [6, 5, 4], [3, 2, 1]] rotate_rect_array(rnd, 3)==[[7, 4, 1], [8, 5, 2], [9, 6, 3]] def adjacent_coords(X1:int, Y1:int, X2:int, Y2:int) -> bool: # return True if pair of coordinates laying adjacently: vertically/horizontally/diagonally: return any([X1==X2 and Y1==Y2+1, X1==X2 and Y1==Y2-1, X1==X2+1 and Y1==Y2, X1==X2-1 and Y1==Y2, X1==X2-1 and Y1==Y2-1, X1==X2-1 and Y1==Y2+1, X1==X2+1 and Y1==Y2-1, X1==X2+1 and Y1==Y2+1]) def ANSI_set_normal_color(color): return '\033[%dm' % (color+31) def ANSI_set_background_color(color): return '\033[%dm' % (color+41) def ANSI_reset(): return '\033[0m' # by 5 parts # print (my_utils.partition (list(range(20)), 5)) # return -> [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19]] def partition(lst:List[Any], n:int) -> List[Any]: division = len(lst) / float(n) return [ lst[int(round(division * i)): int(round(division * (i + 1)))] for i in range(n) ] def is_in_range_incl (v, low, high): if v>=low and v<=high: return True return False def find_1st_elem_GE (array, v): for a in array: if a>=v: return a return None # not found def find_1st_elem_LE (array, v): #print (array) for a in array[::-1]: if a<=v: return a return None # not found def list_of_strings_to_list_of_ints (l): return list(map(lambda x: int(x), l)) # I use this to convert f##king JSON keys from strings to ints def string_keys_to_integers(d): rt={} for k in d: if type(d[k]) == dict: rt[int(k)]=string_keys_to_integers(d[k]) # recursively else: rt[int(k)]=d[k] return rt def element_in_array_is_in_range (array:List[Any], low, high) -> bool: for a in array: if is_in_range_incl(a, low, high): return True return False def ceil_binlog(x:int) -> int: return math.ceil(math.log(x, 2)) # SageMath style # for example, poly=0x1EDC6F41 (CRC-32C (Castagnoli)) # output = "a^28 + a^27 + a^26 + a^25 + a^23 + a^22 + a^20 + a^19 + a^18 + a^14 + a^13 + a^11 + a^10 + a^9 + a^8 + a^6 + 1" def poly_to_str(poly:int) -> str: rt=[] size=ceil_binlog(poly) for i in range(size, -1, -1): if ((poly>>i)&1)==1: if i==0: rt.append("1") elif i==1: rt.append("a") else: rt.append("a^"+str(i)) return " + ".join(rt) def human(seconds:int) -> str: if seconds==0: return "0s" minutes=0 hours=0 days=0 if seconds>=60: minutes = seconds // 60 seconds = seconds - minutes*60 if minutes>=60: hours = minutes // 60 minutes = minutes - hours*60 if hours>=24: days = hours // 24 hours = hours - days*24 rt="" if days>0: rt=rt+str(days)+"d" if hours>0: rt=rt+str(hours)+"h" if minutes>0: rt=rt+str(minutes)+"m" if seconds>0: rt=rt+str(seconds)+"s" return rt def transpose_matrix(m): """ # longer and verbose. but equivalent: rt=[] for x in zip(*m): rt.append(list(x)) return rt """ return [list(x) for x in zip(*m)] # yet unused # TODO: test rectangles def transpose_matrix_test(): rnd=[[1,2,3],[4,5,6],[7,8,9]] assert transpose_matrix(rnd)==[[1, 4, 7], [2, 5, 8], [3, 6, 9]] # NOT USED: begin vvv def pad_list_of_strings_by_max_string (l:List[str]) -> List[str]: return list(map(lambda s: s.ljust(max(map(len, l))), l)) def pad_list_of_strings_by_max_string_test(): lst=["x", "y", "foo", "bar", "asdf"] # this will print: ['x ', 'y ', 'foo ', 'bar ', 'asdf'] print (pad_list_of_strings_by_max_string(lst)) def concat_list_of_strings_side_by_side(lst:List[List[str]]) -> List[str]: t=transpose_matrix(lst) return ["".join(x) for x in t] """ this will print: column 1 | 2nd column foo | x bar | y asd | ______ 0 | 01234 1 | | 20 """ def concat_list_of_strings_side_by_side_test(): l1=["column 1", "foo", "bar", "asd", "0", "1", ""] l2=[" | "]*len(l1) l3=["2nd column", "x", "y", "______", "01234", "", "20"] l1_padded=pad_list_of_strings_by_max_string (l1) l2_padded=pad_list_of_strings_by_max_string (l2) l3_padded=pad_list_of_strings_by_max_string (l3) for l in concat_list_of_strings_side_by_side([l1_padded, l2_padded, l3_padded]): print (l) # NOT USED: end ^^^ # gen random 32 bits def get_32_bits_from_urandom(): return int.from_bytes(os.urandom(4), byteorder='big')&0xffffffff def uniq_list(lst): return list(set(lst))