Julia equivalent to python list multiplication - list

In python I can quickly concatenate and create lists with repeated elements using the + and * operators. For example:
my_list = [1] * 3 + ['a'] * 4 # == [1, 1, 1, 'a', 'a', 'a', 'a']
Similarly in Julia, I can quickly concatenate and create strings with repeated elements using the * and ^ operators. For example:
my_string = "1"^3 * "a"^4 # == "111aaaa"
My question is whether or not there is a convenient equivalent for lists (arrays) in Julia. If not, then what is the simplest way to define arrays with repeated elements and concatenation?

For the above scenario, a shorter form is fill:
[fill(1,3); fill('a', 4)]
You could also define a Python style operator if you like:
⊕(a::AbstractVector{T}, n::Integer) where T = repeat(a, n)
⊕(a::T, n::Integer) where T = fill(a, n)
The symbol ⊕ can be entered in Julia by typing \oplus and pressing Tab.
Now you can do just as in Python:
julia> [1,2] ⊕ 2
4-element Vector{Int64}:
1
2
1
2
julia> 3 ⊕ 2
2-element Vector{Int64}:
3
3

You can use repeat, e.g.
[repeat([1], 3); repeat(['a'],4)]
produces Any[1, 1, 1, 'a', 'a', 'a', 'a'].

Related

Is there a non-hack way to print continued fractions in SymPy with integers without evaluation?

I would like to see continued fractions with integers displayed in that form with SymPy, but I cannot seem to make SymPy comply. I found this Stack Overflow question and answer very useful (see farther below), but cannot reach my target goal here:
This is the continued fraction expansion of $\frac{13}{5}$. A common notation for this expansion is to give only the boxed terms as does SymPy below, i.e., $[2,1,1,2]$ from the SymPy continued_fraction_iterator:
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
print( Rat_13_5 )
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
( Rat_13_5 )
print( Rat_13_5 )
With output [2, 1, 1, 2].
Pg 37 of the Sympy manual release 1.5 Dec 9, 2019 gives a code snippet to print such an expanded fraction list:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr += i
expr = 1/expr
return l[0] + expr
If you invoke list_to_frac with the Rat_13_5 continued fraction expansion list, SymPy takes off and evaluates it:
print( list_to_frac( Rat_13_5 ) )
with output 13/5
If you use a list of symbols instead, then list_to_frac prints the desired continued fraction, e.g.,
n1, n2, n3, n4, n5, n6, n7, n8, n9 = symbols('n1:10')
cont_frac_list = [n2, n1, n1, n2]
contfrac12201015 = list_to_frac( [n2,n1,n1,n2] )
contfrac122010154
Which produces the desired (I am working in a JupyterLab environment so am actually obtaining typset LaTeX output throughout):
n2 + 1/(n1 + 1/(n1 + 1/n2))
I rewrote list_to_frac to use the UnevaluatedExpr facility presented by Francesco in the StackOverflow question I cited earlier:
def list_to_frac_noEval(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = UnevaluatedExpr(expr + i)
expr = UnevaluatedExpr( 1/expr )
return l[0] + expr
Invoking list_to_frac_noEval on the $\frac{13}{5}$ expansion list:
list_to_frac_noEval( [2,1,1,2] )
I obtain output
2 + (1 + (1 + 2**(-1))**(-1))**(-1)
Some folks use that notation (so I wanted to share list_to_frac_noEval in any case, that being superior to ending up with an evaluated single rational if you want to see the continued fraction), for example Roger Penrose in section $\unicode{x00A7}3.2$ of The Road to Reality (2004), but I still find it annoying that I cannot obtain the explicit continued fraction format when using integers instead of symbols.
I experimented with substituting in integers for symbols with evaluate=False, using both the subs method and the Subs function, looked at various combinations of sympify and srepr and parse_expr with evaluate=False, , but cannot persuade SymPy 1.4 to print the explicit fraction form that I obtain with list_to_frac operating on symbol arguments. Is there a way to accomplish this short of modifying SymPy code or special casing a particular set of numbers?
You can construct the expression explicitly passing evaluate=False to each part of the expression tree:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = Add(i, expr, evaluate=False)
expr = Pow(expr, -1, evaluate=False)
return Add(l[0], expr, evaluate=False)
That gives:
In [2]: nums = list(continued_fraction_iterator(Rational(13, 5)))
In [3]: nums
Out[3]: [2, 1, 1, 2]
In [4]: list_to_frac(nums)
Out[4]:
1
───────────── + 2
1
───────── + 1
1
───── + 1
0 + 2
It looks like it's the wrong way around but that's just the way the printing works with default settings:
In [5]: init_printing(order='old')
In [6]: list_to_frac(nums)
Out[6]:
1
2 + ─────────────
1
1 + ─────────
1
1 + ─────
0 + 2
You can trigger evaluation with doit:
In [7]: _.doit()
Out[7]: 13/5

Using Pandas to subset data from a dataframe based on multiple columns?

I am new to python. I have to extract a subset from pandas dataframe based on 2 lists corresponding to 2 columns in that dataframe. Both the values in list should match with that of dataframe at index level. I have tried with "isin" function but obviously it doesn't work with combinations.
from pandas import *
d = {'A' : ['a', 'a', 'c', 'a','b'] ,'B' : [1, 2, 1, 4,1]}
df = DataFrame(d)
list1 = ['a','b']
list2 = [1,2]
print df
A B
0 a 1
1 a 2
2 c 1
3 a 4
4 b 1
### Using isin function
df[(df.A.isin(list1)) & (df.B.isin(list2)) ]
A B
0 a 1
1 a 2
4 b 1
###Desired outcome
d2 = {'A' : ['a'], 'B':[1]}
DataFrame(d2)
A B
0 a 1
Please let me know if this can be done without using loops and if there is a way to do it in a single step.
A quick and dirty way to do this is using zip:
df['C'] = zip(df['A'], df['B'])
list3 = zip(list1, list2)
d2 = df[df['C'].isin(list3)
print(df2)
A B C
0 a 1 (a, 1)
You can of course drop the newly created column after you're done filtering on it.

Combining values from an arbitrary number of pandas columns into a new column — a 'join' in the not-SQL sense

I'm trying to do what's described here, but it's not the case that only one of my columns is populated, and I want to have a delimiter.
The code I'd like to replace (with something that will take an arbitrary number of k's) is:
raw_df["all ks"] = raw_df["k1"].fillna("") + "/" + \
raw_df["k2"].fillna("") + "/" + \
raw_df["k3"].fillna("") + "/" + \
raw_df["k4"].fillna("")
I wondered if this solution could be somehow responsive, but I'm hoping for something simpler.
Thanks for any helpful suggestions. Searching the web has been frustrating because I'm trying to do a join (in the pythonic sense) and most search results relate to joining columns in the database sense (including as adapted in pandas).
You could use the cat string method to concatenate the string values. With this method you can specify the delimiter and what the NaN values should be replaced with.
For example, here's a DataFrame:
>>> df = pd.DataFrame({'a': ['x', np.nan, 'x'],
'b': ['y', 'y', np.nan],
'c': ['z', 'z', np.nan]})
a b c
0 x y z
1 NaN y z
2 x NaN NaN
Then starting with column a and passing in the remaining columns using a list comprehension:
>>> df['a'].str.cat(others=[df[col] for col in df.columns[1:]],
sep='/', na_rep='')
0 x/y/z
1 /y/z
2 x//
So this is what I came up. It uses Apply() and a function. Not as concise as I hoped, but it works with an arbitrary number of Ks. Maybe someone will come up with something better
Generating a dataframe
d = {'k1' : [np.nan,'a','b'], 'k2' : ['c', np.nan, 'c'], 'k3' : ['r','t',np.nan], 'k4': [np.nan,'t','e']}
raw_df = pd.DataFrame(d)
raw_df
k1 k2 k3 k4
0 Nan c r Nan
1 a Nan t t
2 b c Nan e
define a function
def concatKs(s):
allK = ''
for k in s:
if k is not np.nan:
allK += k + '/'
else:
allK += '' + '/'
return allK
then the apply() and passing our function
raw_df['all ks'] = raw_df.apply(concatKs, axis=1)
raw_df
k1 k2 k3 k4 all ks
0 NaN c r NaN /c/r//
1 a NaN t t a//t/t/
2 b c NaN e b/c//e/

Split if two consecutive characters are not same

I have a input string like
a = '4433555555666666'
i want the values to be separated if last character is not same as the next one.
in this case:
44, 33, 555555, 666666
I'm new in python so don't know how to deal with it. I have tried but it just gives first one correct i.e.
['44', '', '555555666666']
Also if two consecutive character group is same.
i.e.
a = 'chchdfch'
then 'ch' should be replaced with
a = '**df*'
You can use itertools.groupby()
[''.join(v) for k, v in itertools.groupby(a)]
Demo:
>>> import itertools
>>> a = '4433555555666666'
>>> [''.join(value) for key, value in itertools.groupby(a)]
['44', '33', '555555', '666666']
So this code is called a list comprehension - a compact way of iterating over elements individually.
Another way of representing this is:
>>> for k, v in itertools.groupby(a):
... print k, v
...
4 <itertools._grouper object at 0x100b90710>
3 <itertools._grouper object at 0x100b90750>
5 <itertools._grouper object at 0x100b90710>
6 <itertools._grouper object at 0x100b90750>
>>> for k, v in itertools.groupby(a):
... print k, "".join(v)
...
4 44
3 33
5 555555
6 666666
>>>
Just ignore the k the iterator generates.

Can I combine a list of similar dataframes into a single dataframe? [duplicate]

This question already has answers here:
Combine a list of data frames into one data frame by row
(10 answers)
Closed 4 years ago.
I have a dataframe:
foo <- list(df1 = data.frame(x=c('a', 'b', 'c'),y = c(1,2,3)),
df2 = data.frame(x=c('d', 'e', 'f'),y = c(4,5,6)))
Can I convert it to a single dataframe of the form:
data.frame(x = c('a', 'b', 'c', 'd', 'e', 'f'), y= c(1,2,3,4,5,6))
?
do.call("rbind", foo) should do the trick.
with plyr:
foo <- list(df1 = data.frame(x=c('a', 'b', 'c'),y = c(1,2,3)),
df2 = data.frame(x=c('d', 'e', 'f'),y = c(4,5,6)))
library(plyr)
ldply(foo)[,-1]
x y
1 a 1
2 b 2
3 c 3
4 d 4
5 e 5
6 f 6
There are several problems with your code.
The first is that the assignment statement in the list doesn't work. This needs to be fixed by, for example:
foo <- list(
df1 = data.frame(x=c('a', 'b', 'c'), y = c(1,2,3)),
df2 = data.frame(x=c('d', 'e', 'f'), y = c(4,5,6))
)
You can then use rbind() to combine the data frames:
rbind(foo$df1, foo$df2)
x y
1 a 1
2 b 2
3 c 3
4 d 4
5 e 5
6 f 6
But this poses more questions. For example, why do you combine the data frames in a list in the first place. The second is whether you really need to use data frames rather than vectors. Finally, I generally try to avoid rbind() and rather use merge() when combining data frames in this way.
How about merge(foo[[1]], foo[[2]], all = TRUE)