amend a subarray in place in j? - j

I've got two ways to amend a subarray in J but I don't like either of them.
(Imagine selecting a rectangle in a paint program and applying some arbitrary
operation to that rectangle in place.)
t =. i. 10 10 NB. table to modify
xy=. 2 3 [ wh =. 3 2 NB. region i want want to modify
u =. -#|. NB. operation to perform on region
I can fetch the subarray and apply the
operation in one step with cut (;.0):
st =. ((,./xy),:(|,./wh)) u;.0 t
Putting it back is easy enough, but seems to require
building a large boxed array of indices:
(,st) (xy&+each,{;&:i./wh) } t
I also tried recursively splitting and glueing
the table into four "window panes" at a time:
split =: {. ; }. NB. split y into 2 subarrays at index x
panes =: {{ 2 2$ ; |:L:0 X split&|:&.> Y split y [ 'Y X'=.x }}
glue =: [: ,&>/ ,.&.>/"1 NB. reassamble
xy panes t
┌────────┬────────────────────┐
│ 0 1 2│ 3 4 5 6 7 8 9│
│10 11 12│13 14 15 16 17 18 19│
├────────┼────────────────────┤
│20 21 22│23 24 25 26 27 28 29│
│30 31 32│33 34 35 36 37 38 39│
│40 41 42│43 44 45 46 47 48 49│
│50 51 52│53 54 55 56 57 58 59│
│60 61 62│63 64 65 66 67 68 69│
│70 71 72│73 74 75 76 77 78 79│
│80 81 82│83 84 85 86 87 88 89│
│90 91 92│93 94 95 96 97 98 99│
└────────┴────────────────────┘
NB. then split the lower right pane again,
NB. extract *its* upper left pane...
s0 =. 1 1 {:: p0 =. xy panes t
s1 =. 0 0 {:: p1 =. wh panes s0
NB. apply the operation and reassemble:
p1a =. (<u s1) (<0 0) } p1
glue (<glue p1a) (<1 1) } p0
The first approach seems to be the quicker and
easier option, but it feels like there ought
to be a more primitive way to apply a verb at
a sub-array without extracting it, or to paste
in a subarray at some coordinates without manually
creating the array of indices for each element.
Have I missed a better option?

I would begin by creating the set of indices that I wanted to amend
[ ind =. < xy + each i. each wh
┌───────────┐
│┌─────┬───┐│
││2 3 4│3 4││
│└─────┴───┘│
└───────────┘
I can use those to select the atoms I want from t
ind { t
23 24
33 34
43 44
And if I can select with them then I can use the same indices to amend t
_ ind } t
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 _ _ 25 26 27 28 29
30 31 32 _ _ 35 36 37 38 39
40 41 42 _ _ 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99
and finally I can use a hook with the left tine being ind}~ after preprocessing t with the right tine (ind u#{ ]) to get my result
(ind}~ ind u#{ ]) t
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 _43 _44 25 26 27 28 29
30 31 32 _33 _34 35 36 37 38 39
40 41 42 _23 _24 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99
You actually gave me the solution when you asked how you can 'amend' your array in place.

Related

Python-3 - get values from list by frequency and then by the values with equal counts in descending order

I have list of integers, from which I would first like to get unique numbers, first ordered by their occurrences and then the numbers with equal counts should be ordered in descending order.
example 1:
input1 = [1,2,2,1,6,2,1,7]
expected output = [2,1,7,6]
explanation: both 2 and 1 appear thrice while 6 and 7 appear once. so, the numbers occurring thrice will be placed first and in descending order; and same for the set that appears once.
another example case:
input_2 = list(map(int, '40 29 2 44 30 79 46 85 118 66 113 52 55 63 48 99 123 51 110 66 40 115 107 46 6 114 36 99 13 108 85 39 14 121 42 37 56 11 104 28 24 123 63 51 118 52 120 28 64 43 44 86 42 71 101 78 93 1 6 14 42 33 88 107 35 70 74 30 54 76 27 91 115 71 63 103 94 109 39 4 16 108 97 83 29 57 86 121 53 94 28 7 5 31 123 21 2 17 112 104 75 124 88 30 108 14 65 118 28 81 80 14 14 107 21 60 47 97 50 53 19 112 43 46'.split()))
output_2 = list(map(int, '14 28 123 118 108 107 63 46 42 30 121 115 112 104 99 97 94 88 86 85 71 66 53 52 51 44 43 40 39 29 21 6 2 124 120 114 113 110 109 103 101 93 91 83 81 80 79 78 76 75 74 70 65 64 60 57 56 55 54 50 48 47 37 36 35 33 31 27 24 19 17 16 13 11 7 5 4 1'.split()))
This was from a coding test I took. This must be solved without using functions from imports like collections, itertools etc,. and using functions already available in python's namespace like dict, sorted is allowed. How do I do this as efficiently as possible?
def sort_sort(input1):
a = {i:input1.count(i) for i in set(input1)}
b ={i:[] for i in set(a.values())}
for k,v in a.items():
b[v].append(k)
for v in b.values():
v.sort(reverse=True)
output=[]
quays =list(b.keys())
quays.sort(reverse=True)
for q in quays:
output +=b[q]
print(output)

Why are the results of these two commands different?

The result of this command(ls -d [!0-99]) already contains this command(ls -d [!0-100]).But in my mind, the results of these two commands should be the same.Who can help me explain the result of the second command?
jack#DESKTOP-KRIB7TB:~$ ls -d [!0-99]*
a b c d e f g h i j k
jack#DESKTOP-KRIB7TB:~$ ls -d [!0-100]*
2 25 30 36 41 47 52 58 63 69 74 8 85 90 96 c i
20 26 31 37 42 48 53 59 64 7 75 80 86 91 97 d j
21 27 32 38 43 49 54 6 65 70 76 81 87 92 98 e k
22 28 33 39 44 5 55 60 66 71 77 82 88 93 99 f
23 29 34 4 45 50 56 61 67 72 78 83 89 94 a g
24 3 35 40 46 51 57 62 68 73 79 84 9 95 b h
The [...] syntax in a glob is a per-character match, not a numeric range. [a-c] is the same as [abc], for instance. You can have multiple ranges or individual characters in a block, so [a-cfh-k] is the same as [abcfhijk].
So [!0-99] is the same as [!01234567899] (notice the redundant 9), whereas [!0-100] is the same as [!0100], thereby only matching 0s and 1s.
You can list all non-digit directories with ls -d [!0-9]*, but I don't know that there's a robust way (with globs and ls) to list directories with names that are numerals greater than 100.

Convert one column of numbers on excel into multiple columns

I need to Convert one large column on windows excel 2016 of numbers into multiple columns of 10 rows each.
I am currently doing this manually. Please help me Stackoverflow! :)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
The results should be this:
1 11
2 12
3 13
4 14
5 15
6 16
7 17
8 18
9 19
10 20
and so on....
Try:
Formula in C1:
=INDEX($A:$A,ROW()+((COLUMN(A1)-1)*10))
Drag right and 10 down.

Aligning lines in python

I have written a code to print a snake and ladder grid.
I want the numbers to be aligned such that they are in a straight vertical line.
My code is:
for i in range(100,0,-1):
if i%20 == 0:
for i in range(i,i-10,-1):
print(i, end = " ")
print()
elif i%10 == 0:
for i in range(i-9,i+1):
print(i, end = " ")
print()
The present output is:
100 99 98 97 96 95 94 93 92 91
81 82 83 84 85 86 87 88 89 90
80 79 78 77 76 75 74 73 72 71
61 62 63 64 65 66 67 68 69 70
60 59 58 57 56 55 54 53 52 51
41 42 43 44 45 46 47 48 49 50
40 39 38 37 36 35 34 33 32 31
21 22 23 24 25 26 27 28 29 30
20 19 18 17 16 15 14 13 12 11
1 2 3 4 5 6 7 8 9 10
If you're using Python3, try replacing your:
print(i, end = " ")
lines with:
print(format(i, '6d'), end='')
If you must have the numbers left-justified, try this instead:
print('{:<6d}'.format(i), end='')
These will account for the fact that not every number has the same amount of digits, yet you want every number to take up the same amount of space.

Counting only lines with words in them

How can I numerically count only lines that have words in them? In the example below, I have four lines with words in them:
100314:Status name one: 15
24 1 7 5 43 13 24 64 10 47 31 100 22 20 38 63 49 24 18 82 66 22 21 77 52 8 6 11 50 20 5 1 0
101245:Status name two: 14
2 10 2 2 25 53 3 31 30 1 21 41 9 14 18 40 6 10 18 72 20 16 33 29 19 18 12 60 48 12 8 50 43 13
103765:Yet another name here: 29
45 29 29 475 63 69 47 94 65 65 69 55 53 905 117 57 42 92 90 59 91 52 79 101 192 87 144 74 115 82 78 109 12 96 64 78 111 106 84 19 0 7
102983:Blah blah yada yada: 82
41 37 40 60 82 72 17 41 17 19 43 3
I've tried using different pipe combinations of wc -l and grep/uniq. I also tried counting only the odd lines (which works in the MWE above), but I'm looking for something more general-purpose for a large unstructured dataset.
It depends on how you define a word. If, for example, it's any two consecutive letters, you can just use something like:
grep -E '[a-zA-z]{2}' fileName | wc -l
You can simply adjust the regular expression depending on how you define a word (that one I've provided won't pick up "A" or "I" or "I'm" for example), but the concept will remain the same

Resources