As far as I know, it is impossible to perform array operations on numbers in J; e.g.
NB. In J, this won't work:
m =: 234
+/ m
9
*/ m
24
Since I can't do it directly, is there a way to split a number into a list and back again, like this?:
splitFunction 234
2 3 4
+/ (splitFunction 234)
9
|. (splitFunction 234)
4 3 2
concatenateFunction (4 3 2)
432
If it is not possible, is there a way to turn a number into a string, and back again? (since J treats strings as character arrays) e.g.
|. (toString 234)
432
Well, there is a little bit to unpack here in what your expectations would be. Let's start with
m=:234 NB. m is the integer 234
+/ m NB. +/ sums across the items - only item is 234
234
*/ m NB. */ product across the items - only item is 234
234
so there seems to be confusion between the digits of the integer 234, which would be 2 3 4 and the fact that 234 is an atom that has only one item which has a value of 234.
Moving on from that, you can deconstruct your integer using 10 & #. ^: _1 which consists of the inverse (^:_1) of Base (#.) with a left argument of 10 which allows the break up to be done in base 10. J's way of inverting a primitive is to use the Power conjunction (^:) raised to the negative 1 (_1)
splitFunction =: 10 & #.^:_1
concatenateFunction =: 10 & #.
splitFunction 234
2 3 4
+/ splitFunction 234
9
*/ splitFunction 234
24
|. splitFunction 234
4 3 2
concatenateFunction 2 3 4
234
concatenateFunction splitFunction 234
234
I think that this will do what you want, but you may want to spend a bit more time thinking about what you would have expected +/ 234 to do and whether this would be useful behaviour.
Related
Is it possible to align the spaces and characters of two strings perfectly?
I have two functions, resulting in two strings.
One just adds a " " between a list of digits:
digits = 34567
new_digits = 3 4 5 6 7
The second function takes the string and prints out the index of the string, such that:
digits = 34567
index_of_digits = 1 2 3 4 5
Now the issue that I am having is when the length of the string is greater than 10, the alignment is off:
I am supposed to get something like this:
Please advice.
If your digits are in a list, you can use format to space them uniformly:
L = [3,4,2,5,6,3,6,2,5,1,4,1]
print(''.join([format(n,'3') for n in range(1,len(L)+1)]))
print(''.join([format(n,'3') for n in L]))
Or with f-string formatting (Python 3.6+):
L = [3,4,2,5,6,3,6,2,5,1,4,1]
print(''.join([f'{n+1:3}' for n in range(len(L))]))
print(''.join([f'{n:3}' for n in L]))
Output:
1 2 3 4 5 6 7 8 9 10 11 12
3 4 2 5 6 3 6 2 5 1 4 1
Ref: join, format, range, list comprehensions
The rather verbose fork I came up with is
({. , (>:#[ }. ]))
E.g.,
3 ({. , (>:#[ }. ])) 0 1 2 3 4 5
0 1 2 4 5
Works great, but is there a more idiomatic way? What is the usual way to do this in J?
Yes, the J-way is to use a 3-level boxing:
(<<<5) { i.10
0 1 2 3 4 6 7 8 9
(<<<1 3) { i.10
0 2 4 5 6 7 8 9
It's a small note in the dictionary for {:
Note that the result in the very last dyadic example, that is, (<<<_1){m , is all except the last item.
and a bit more in Learning J: Chapter 6 - Indexing: 6.2.5 Excluding Things.
Another approach is to use the monadic and dyadic forms of # (Tally and Copy). This idiom of using Copy to remove an item is something that I use frequently.
The hook (i. i.##) uses Tally (monadic #) and monadic and dyadic i. (Integers and Index of) to generate the filter string:
2 (i. i.##) 'abcde'
1 1 0 1 1
which Copy (dyadic #) uses to omit the appropriate item.
2 ((i. i.##) # ]) 0 1 2 3 4 5
0 1 3 4 5
2 ((i. i.##) # ]) 'abcde'
abde
Unboxing or opening boxes with different sizes causes padding with 0 for numerals and a space with literals:
v=.1 4 8 ; 2 6 4 ; 6 8 4 5; 7 8 9; 6 3 7 4 9
>v
1 4 8 0 0
2 6 4 0 0
6 8 4 5 0
7 8 9 0 0
6 3 7 4 9
The fit (!.) conjunction is usually the thing to use for these things, but
>!. _1 v
Is not supported and throws a domain error.
I've got this, but with very large arrays it's not very fast:
(>./ # every y) {.!. _1 every y
Is there an efficient way to define the padding value for opening boxes?
Setting
f =: 3 :'(>./ # every y) {.!. _1 every y'
g =: _1&paddedOpen
and (in the same spirit as your f):
h =: 3 : '((>./# &> y)&($!._1))#> y'
I get the following performances for time and space:
(100&(6!:2) ,: 7!:2) &.> 'f L';'g L';'h L'
┌─────────┬─────────┬─────────┐
│ 0.045602│0.0832403│0.0388146│
│4.72538e6│1.76356e7│4.72538e6│
└─────────┴─────────┴─────────┘
where L is a large array:
L =. (<#(+i.)/)"1 ? 50000 2 $ 10
You can slightly improve f by making it terse; for example:
f =: ] {.!._1&>~ >./#:(#&>)
I don't think that there is much room for more improvements.
My guess is that doing the padding directly will be the path to efficiency, especially if the need is restricted to a specific structure of data (as perhaps suggested by your example.) This solution has not been subjected to performance analysis, but it shows one way to do the padding yourself.
Here I'm making the assumption that the task involves always going from boxed lists to a table, and that the data is always numeric. Additional assert. statements may be worth adding to qualify that the right argument is as expected.
v=.1 4 8 ; 2 6 4 ; 6 8 4 5; 7 8 9; 6 3 7 4 9 NB. example data
paddedOpen=: dyad define
assert. 0 = # $ x
Lengths=. #&> y
PadTo=. >./ Lengths
Padding=. x #~&.> PadTo - Lengths
y ,&> Padding
)
_1 paddedOpen v
1 4 8 _1 _1
2 6 4 _1 _1
6 8 4 5 _1
7 8 9 _1 _1
6 3 7 4 9
It is only important to first pad with a customized value when the default value cannot be used as an intermediary. If the default value can be used in passing, it will be faster to let the default padding occur then replace all default values with the preferred value. From the nature of your question I assume the default value has meaning in the main domain, so simple replacement won't serve.
Please leave comments informing us of the relative performance of different techniques, or at least whether one does or does not prove fast enough for your purposes.
As I remember, the count of combinations equal n!
But, for I example I have string "abc". I want to get all the combinations with different registry: aBc or ABc etc
So, abc is 3 chars. 3! = 1 * 2 * 3 = 6.
But, if I shall try manually do this work - I'll get 8 variations:
1 abc
2 Abc
3 aBc
4 abC
5 ABc
6 aBC
7 AbC
8 ABC
So, it looks like, that answer it 2^3 = 8, but what is 2 ? 3 - is the count of registries in string. what is 2 ? count of registry variants?
If I understand correctly, you want to know for a fixed string how many possible combinations there are with respect to writing the fixed string in mixed capitalization. You are not interested in real permutations of the source string, i.e. you don't wan't to take into account that for abc there is also acb, cab, cba etc. Yes?
If so, for 1 letter we have
a A
for two letters
ab Ab aB AB
and for three letters
abc Abc aBc abC ABc aBC AbC ABC
and so on. If that's the case, then the solution is quite simple if you choose the right underlying model. As you may have noticed, the outcome is regardless of the character sequence we choose - so why not choose all a's:
a A
aa aA Aa AA
aaa aaA aAa aAA Aaa AaA AAa AAA
The pattern is that for each character we have two choices available, either uppercase or lowercase, either set or not set... either 1 or 0 - simply replace a with 0 and A with 1 to get:
0 1
00 01 10 11
000 001 010 011 100 101 110 111
That is actually binary counting! So for n letters the number of possible combinations will be equal to 2^n.
Ah, I think I see what you're saying. If I understand you correctly, you are looking to find all possible ways of capitalizing the letters in a string such that all of the letters aren't of the same case - that is, given abc, you'd produce
abC aBc aBC Abc AbC ABc
But not
abc ABC
Because all letters in those versions have the same case.
If this is what you'd like, the number of ways you can do this in a nonempty string of length n is given by 2n - 2. Intuitively, the rationale behind this is as follows. Given a string of n letters, there are 2n different ways to capitalize all of the letters in that string, since for each character independently of the rest, that letter can be in one of two states (upper case or lower case). If you consider all of those combinations, there are exactly two that you want to disallow - the version where all letters are upper-case, and the version where all letters are lower-case.
In your question, you mentioned that the number of combinations of an n-element sequence is n!. This is not quite right. There are n! permutations of an n-element sequence (assuming each element is distinct). For example, there are 3! = 6 permutations of the sequence abc:
abc acb bac bca cab cba
The fact that there are six ways to capitalize a three-letter sequence without giving all letters the same capitalization and that there are six permutations of abc is a complete coincidence. If you look at more terms of the series, you can see that they only match at two locations (2 and 3):
n = 1 2 3 4 5 6
Permutations (n!) 1 2 6 24 120 720
Mixed-case capitalizations (2^n - 2) 0 2 6 14 30 62
If you allow for more cases than just upper and lower (say, k different versions), then you can generalize this to get the value kn - k, since there are kn different combinations, of which k of them will all have the same capitalization.
Hope this helps!
The i. primitive produces a list of integers:
i. 10
0 1 2 3 4 5 6 7 8 9
If I want to produce several short lists in a row, I do this:
;i."0 each [ 2 3 4
0 1 0 1 2 0 1 2 3
(the result I want)
Boxing (that each) is a crutch here, because without it, i."0 produces a matrix.
i."0 [ 2 3 4
0 1 0 0
0 1 2 0
0 1 2 3
(the result I don't want)
Is there a better way to not have i."0 format the output to a matrix, but an array?
No, I believe you can't do any better than your current solution. There is no way for i."0 to return a vector.
The "0 adverb forces i. to accept scalars, and i. returns vectors. i. has no way of knowing that your input was a vector rather than a scalar. According to The J primer the result shape is the concatenation of the frame of the argument and the result.
The shortest "box-less" solution I've found so far is
(*#$"0~#&,i."0) 2 3 4
which is still longer than just using ;i. each 2 3 4