Remove last n elements of a vec, by chunks - rust

Having a vec![1,2,3,4,5,6,7,8,9,10,11,12] I would like to remove, in chunks of 6 elements, the last 3 elements, so the result would be a slice or vec like [1,2,3,7,8,9]. Is there an easy way of doing that without intermediate allocations (like collecting small vecs), preferably using iterators?
Thanks!

I would just filter based on the index (which you can get with .enumerate())
fn main() {
let data = vec![1,2,3,4,5,6,7,8,9,10,11,12];
let new_data: Vec<i32> = data.iter()
.enumerate()
.filter(|(i, _)| (*i / 3) % 2 == 0)
.map(|(_, v)| *v) // you could have this be Vec<&i32>, but I don't think you'd save memory/time. if it was a more complex data type, references would save memory and time
.collect();
println!("{new_data:?}");
}
0 / 3 == 0, 0 % 2 == 0, ? 0 == 0 -> true so keep
1 / 3 == 0, 0 % 2 == 0, ? 0 == 0 -> true so keep
2 / 3 == 0, 0 % 2 == 0, ? 0 == 0 -> true so keep
3 / 3 == 1, 1 % 2 == 1, ? 1 == 0 -> false so skip
4 / 3 == 1, 1 % 2 == 1, ? 1 == 0 -> false so skip
5 / 3 == 1, 1 % 2 == 1, ? 1 == 0 -> false so skip
6 / 3 == 2, 2 % 2 == 0, ? 0 == 0 -> true so keep
...

Related

Hackerrank - why is my output being written one character at a time?

I am solving the following "Vertical Sticks "hackerrank challenge: https://www.hackerrank.com/challenges/vertical-sticks/problem?isFullScreen=true&h_r=next-challenge&h_v=zen&h_r=next-challenge&h_v=zen
Here is my solution:
def solve(y):
out = []
x = list(itertools.permutations(y))
for yp in x:
arr = []
arr.append(1)
for i in range(int(1),int(len(yp))):
#flag = 0
for j in range(int(i-1),int(-1),int(-1)):
if yp[j] >= yp[i]:
arr.append(i-j)
#flag+=1
break
if j==0:
arr.append(i+1)
out.append(sum(arr))
p = round((sum(out)/len(out)),2)
pp = "%0.2f" % (p)
print(pp)
return pp
if __name__ == '__main__':
fptr = open(os.environ['OUTPUT_PATH'], 'w')
t = int(input().strip())
for t_itr in range(t):
y_count = int(input().strip())
y = list(map(int, input().rstrip().split()))
result = solve(y)
fptr.write('\n'.join(map(str, result)))
fptr.write('\n')
fptr.close()
My print(pp) output comes out correctly for the test case as:
4.33
3.00
4.00
6.00
5.80
11.15
But my return pp stdout comes out as:
4
.
3
3
3
.
0
0
4
.
0
0
6
.
0
0
5
.
8
0
1
1
.
1
5
i.e. one character per line, and is classified incorrect. Could somebody point me into the direction of why this is?
The return from solve is already a string. When you call join on it, you are splitting it into its individual characters, separated by newlines.

How to create a loop that iterates adding logical test to an if

I find my self trying to analyse a data set and find how some variables correlate.
I need to add a loop that adds a logical test to the if statement:
Edited:
Example:
Take this data frame as example
In [11]: df
Out[11]:
INPUT1 INPUT2 INPUT3 ... OUTPUT
0 8 5 6 ... 1
1 3 2 5 ... 0
2 3 1 5 ... 1
3 1 2 5 ... 0
4 4 3 5 ... 0
I'm testing the combinations of inputs to check how they match the output
def greater_than(a,b):
return a > b
def greater_equal_than(a,b):
return a >= b
def lower_equal_than(a,b):
return a <= b
def lower_than(a,b):
return a < b
def equal(a,b):
return a == b
operation = { '>': greater_than, '>=': greater_equal_than, '<=': lower_equal_than, '<': lower_than }
escenario = pd.DataFrame(columns=['esc','pf'])
for i in range(len(names)):
for j in names[i+1:]:
for op in operation:
escenario['esc'] = df.apply(lambda x : 1 if operation[op]( names[i], j ) else 0, axis=1)
escenario['pf'] = df['OUTPUT']
match = escenario.apply(lambda x : 1 if x['pf'] == 1 and x['pf'] == x['esc'] else 0, axis=1 )
percent_match = (100 * match.sum())/escenario['pf'].sum()
percent_no_match = (100 *(escenario['esc'].sum() - match.sum())) / escenario['esc'].sum()
print( f"{names[i]} {op} {j} -> { percent_match } / {percent_no_match} " )
I need to check all the combinations of input combinations that keeps percent_match closer to a 100% and percent_no_match closer to 0%
for example:
first iteration:
INPUT2 < INPUT3
SECOND INTERATION
INPUT2 < INPUT3 and INPUT1 > INPUT2
Right now I'm running the code, sorting the print and getting the couple where the match is closer to 100 and the modifying the code to add the match, Example:
First run better output is INPUT2 < INPUT3
Then I modify this line:
escenario['esc'] = df.apply(lambda x : 1 if operation[op]( names[i], j ) else 0, axis=1)
to add the first output, like:
escenario['esc'] = df.apply(lambda x : 1 if df['INPUT2'] < DF['INPUT3'] and operation[op]( names[i], j ) else 0, axis=1)
and check again...
This last part is the one I want to automate through a loop.
Thanks
I found self modifying python script that fits perfectly into my need.
It allows to recreate a function about of a text string and that's exactly what I need.
Thanks!

How to find maximum count of consecutive zeros in column pandas?

I have dataframe and want to check maximum count of consecutive zero values in Column B.
Example input and output:
df = pd.DataFrame({'B':[1,3,4,0,0,11,1,15,0,0,0,87]})
df_out = pd.DataFrame({'max_count':[3]})
How could this be done?
One NumPy way -
a = df['B'].values
m1 = np.r_[False, a==0, False]
idx = np.flatnonzero(m1[:-1] != m1[1:])
out = (idx[1::2]-idx[::2]).max()
Step-by-step run -
# Input data as array
In [83]: a
Out[83]: array([ 1, 3, 4, 0, 0, 11, 1, 15, 0, 0, 0, 87])
# Mask of starts and ends for each island of 0s
In [193]: m1
Out[193]:
array([False, False, False, False, True, True, False, False, False,
True, True, True, False, False])
# Indices of those starts and ends
In [85]: idx
Out[85]: array([ 3, 5, 8, 11])
# Finally the differencing between starts and ends and max for final o/p
In [86]: out
Out[86]: 3
That could be converted to a one-liner :
np.diff(np.flatnonzero(np.diff(np.r_[0,a==0,0])).reshape(-1,2),axis=1).max()
You can create group for consecutive rows
# create group for consecutive numbers
df['grp'] = (df['B'] != df['B'].shift()).cumsum()
B grp
0 1 1
1 3 2
2 4 3
3 0 4
4 0 4
5 11 5
6 1 6
7 15 7
8 0 8
9 0 8
10 0 8
11 87 9
# check size of groups having 0 value
max_count = df.query("B == 0").groupby('grp').size().max()
print(max_count)
3
Idea is create mask with cumulative sum for counter of consecutive values, filter only 0 values, count them by Series.value_counts and get maximum value:
s = df['B'].ne(0)
a = s.cumsum()[~s].value_counts().max()
print (a)
3
df_out=pd.DataFrame({'max_count':[a]})
Details:
print (s.cumsum())
0 1
1 2
2 3
3 3
4 3
5 4
6 5
7 6
8 6
9 6
10 6
11 7
Name: B, dtype: int32
print (s.cumsum()[~s])
3 3
4 3
8 6
9 6
10 6
Name: B, dtype: int32
print (s.cumsum()[~s].value_counts())
6 3
3 2
Name: B, dtype: int64
Maybe you could adjust it to Python. In Java, you could find most consecutive 0's length using this code:
int B [] = {1,3,4,0,0,11,1,15,0,0,0,87}
int max_zeroes = 0;
int zeroes = 0;
for(int i = 0; i < B.length; i++) {
if( B[i] == 0) {
zeroes += 1;
if(zeroes > max_zeroes) {
max_zeroes = zeroes;
}
} else {
zeroes = 0;
}
}
And if you are inclined towards finding the start and end indexes of most consecutive 0s in an array, you could use this logic:
int max_zeroes = 0;
int zeroes = 0;
int endIndex = -1;
for (int i = 0; i < B.length; i++) {
if (B[i] == 0) {
zeroes += 1;
if (zeroes > max_zeroes) {
max_zeroes = zeroes;
endIndex = i;
}
} else {
zeroes = 0;
}
}
int startIndex = endIndex;
for (int i = endIndex - 1; i > -1; i--) {
if(B[i] == 0) {
start = i;
} else {
i = -1; //used to get out of this for loop.
}
}
System.out.println("Max zeroes is: " + max_zeroes + " at start index " + start + " and end index: " + endIndex);
Maybe you could adjust it to Python.

Path finding: A star not same length from A to B than from B to A

I am implementing the A star algorithm with the Manhattan distance for the 8 puzzle. [ The solution is in spiral form]
1 2 3
8 0 4
7 6 5
In some case, going from A to B will not take the same number of steps as going from B to A.
I think this is because it does not pick the same state on the open list, when they have the same cost, thus, not expanding the same nodes.
From
7 6 4
1 0 8
2 3 5
(A -> B)
7 6 4
1 8 0
2 3 5
(B -> A)
7 6 4
1 3 8
2 0 5
Which both have the same value using Manhattan distance.
Should I explore all path with the same value?
Or should I change the heuristic to have some kind of tie-breaker?
Here is the relevant part of the code
def solve(self):
cost = 0
priority = 0
self.parents[str(self.start)] = (None, 0, 0)
open = p.pr() #priority queue
open.add(0, self.start, cost)
while open:
current = open.get()
if current == self.goal:
return self.print_solution(current)
parent = self.parents[str(current)]
cost = self.parents[str(current)][2] + 1
for new_state in self.get_next_states(current):
if str(new_state[0]) not in self.parents or cost < self.parents[str(new_state[0])][2]:
priority = self.f(new_state) + cost
open.add(priority, new_state[0], cost)
self.parents[str(new_state[0])] = (current, priority, cost)
After wasting so much time re-writing my "solve" function many different ways, for nothing,
I finally found the problem.
def get_next_states(self, mtx, direction):
n = self.n
pos = mtx.index(0)
if direction != 1 and pos < self.length and (pos + 1) % n:
yield (self.swap(pos, pos + 1, mtx),pos, 3)
if direction != 2 and pos < self.length - self.n:
yield (self.swap(pos, pos + n, mtx),pos, 4)
if direction != 3 and pos > 0 and pos % n:
yield (self.swap(pos, pos - 1, mtx),pos, 1)
if direction != 4 and pos > n - 1:
yield (self.swap(pos, pos - n, mtx),pos, 2)
It was in this function. The last if used to be "if 4 and pos > n:"
So there were unexplored states..
2 days for a "-1"
It will teach me to do more unit testing

Sorting a text document python 3

Here's the text document: The first string is the type of metal, the second is the amount of the metal bars, the third is the weight, and the fourth is the value.
Gold 1 5 750
Silver 1 1 400
Rhodium 1 4 500
Platinum 1 6 1000
I have to sort this list by value using insertion sort. Here's what I have so far
def sortMetalsByValuePerBar(metals):
for i in range(1,len(metals)):
j = i
while j > 0 and metals[j-1] > metals[j]:
metals[j - 1], metals[j] = metals[j], metals[j - 1]
j -= 1
return metals
Is this correct?
Try to learn from this solution.
data="""
Gold 1 5 750
Silver 1 1 400
Rhodium 1 4 500
Platinum 1 6 1000
"""
data = filter(None, data.splitlines())
data = [l.split() for l in data]
data = [ (l[0], int(l[1]), int(l[2]), int(l[3])) for l in data ]
def insertion_sort(l, keyfunc=lambda i:i):
for i in range(1, len(l)):
j = i-1
key = l[i]
while keyfunc(l[j]) > keyfunc(key) and (j >= 0):
l[j+1] = l[j]
j -= 1
l[j+1] = key
insertion_sort(data, keyfunc=lambda l: l[3])
for l in data:
print(l)
# Output:
# ('Silver', 1, 1, 400)
# ('Rhodium', 1, 4, 500)
# ('Gold', 1, 5, 750)
# ('Platinum', 1, 6, 1000)

Resources