How to enumerate a slice using the original indices?
enumerate()
returns a sequence of (n, elem)
pairs, where the n
s are consecutive Int
s starting at zero. This makes sense because it is
a protocol extension method for SequenceType
, and an arbitrary sequence
does not necessarily have index associated with the elements.
You would get your expected result with
let powersSlice = slice.indices.map { pow(slice[$0], Double($0)) }
or
let powersSlice = zip(slice.indices, slice).map { pow($1, Double($0)) }
The latter approach could be generalized to a protocol extension
method for arbitrary collections:
extension CollectionType {
func indexEnumerate() -> AnySequence<(index: Index, element: Generator.Element)> {
return AnySequence(zip(indices, self))
}
}
This returns a sequence of (index, elem)
pairs where index
is an index of the collection and elem
the corresponding element.AnySequence
is used to "hide" the specific typeZip2Sequence<RangeGenerator<Self.Index>, Self>
returned from zip()
from the caller.
Example:
let powersSliceEnumerate = slice.indexEnumerate().map() { pow($0.element, Double($0.index)) }
print("powersSliceEnumerate == \(powersSliceEnumerate)")
// powersSliceEnumerate == [2.0, 9.0]
Update for Swift 3:
extension Collection {
func indexEnumerate() -> AnySequence<(Indices.Iterator.Element, Iterator.Element)> {
return AnySequence(zip(indices, self))
}
}
Enumerating sliced array using original indices
The items in the slice always have indexes that are exactly startIndex
less than in the original array:
slice(0, 3) -> [0, 1, 2] -> [0 - 0, 1 - 0, 2 - 0]
slice(3, 6) -> [0, 1, 2] -> [3 - 3, 4 - 3, 5 - 3]
slice(n, …) -> [0, 1, …] -> [n + 0 - n, n + 1 - n, n + 2 - n, …]
So, just adding startIndex
back should do the trick:
/**
* @template Item
* @param {Item[]} items
* @param {number} startIndex
* @param {number} [endIndex]
* @returns {Array<{ item: Item; index: number }>}
*/
function slice(items, startIndex, endIndex = items.length) {
return items.slice(startIndex, endIndex).map((item, index) => ({
item,
index: index + startIndex,
}));
}
function slice(items, startIndex, endIndex = items.length) {
return items.slice(startIndex, endIndex).map((item, index) => ({
item,
index: index + startIndex,
}));
}
const letters = [ ...'abcdefghijklmnopqrstuvwxyz' ];
console.log(slice(letters, 0, 3));
console.log(slice(letters, 3, 6));
console.log(slice(letters, 6, 9));
How to obtain the original indexes from a sliced list in python?
>>> def printy(v):
... for x, y in v:
... print('Original index:', x, ', original element:', y)
...
>>> # Original list
... a = [1, 2, 2, 4, 4, 4, 5, 0]
>>> with_original_indexes = tuple(zip(range(len(a)), a)) # or list()
>>> with_original_indexes = tuple(enumerate(a)) # Equivalent to the above
>>> printy(with_original_indexes)
Original index: 0 , original element: 1
Original index: 1 , original element: 2
Original index: 2 , original element: 2
Original index: 3 , original element: 4
Original index: 4 , original element: 4
Original index: 5 , original element: 4
Original index: 6 , original element: 5
Original index: 7 , original element: 0
>>> printy(with_original_indexes[1:5])
Original index: 1 , original element: 2
Original index: 2 , original element: 2
Original index: 3 , original element: 4
Original index: 4 , original element: 4
>>> printy(with_original_indexes[1:5][2:5])
Original index: 3 , original element: 4
Original index: 4 , original element: 4
>>>
Python: slices of enumerate
You can use islice
:
from itertools import islice
for i,elm in islice(enumerate(some_list),7,40):
print i,elm
Python: enumerate a slice with negative indices
a = [1,2,3,4,5]
print ([c for c in a[-3:]])
Output:
[3,4,5]
With enumerate:
print ([(i, j)[1] for i, j in enumerate(a[-3:])])
Slice a list based on an index and items behind it in Python
Arithmetic with angles
Your goal isn't to slice, concatenate or reverse lists. Your goal is to do basic arithmetic with degrees and keep the results between 0
and 359
. For this, you really should use the modulo operator %
:
>>> 90 % 360
90
>>> 390 % 360
30
>>> -60 % 360
300
>>> 360 % 360
0
Back to the question
If you only want to use this slicing for degrees with a constant increment, you could generate the desired list directly:
>>> STEP = 15
>>> list(range(0, 360, STEP))
[0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300, 315, 330, 345]
>>> def previous_degrees(start, n, step=STEP):
... return [(start - i * step) % 360 for i in range(n + 1)]
...
>>> previous_degrees(90, 12)
[90, 75, 60, 45, 30, 15, 0, 345, 330, 315, 300, 285, 270]
>>> previous_degrees(90, 12, 30)
[90, 60, 30, 0, 330, 300, 270, 240, 210, 180, 150, 120, 90]
>>> previous_degrees(90, 6, 45)
[90, 45, 0, 315, 270, 225, 180]
Your real question
You wrote in a comment:
This array of degrees is designed to work with a smooth rotation
system that I'm trying to create in pygame. Normally I would just find
the difference between the current direction and the target direction
and increment from there, but since the rotation rolls over at zero I
have to hardcode the values to make sure that it will always go the
shortest route possible.
From two angles, you need to determine if you should turn clockwise or anticlockwise. You can use modulo again to make sure that the rotation will be between -180° and 179°:
def shortest_rotation(start_angle, end_angle):
return (end_angle - start_angle + 180) % 360 - 180
Here's an example:
>>> shortest_rotation(0, 90)
90
>>> shortest_rotation(90, 0)
-90
>>> shortest_rotation(90, 90)
0
>>> shortest_rotation(90, 330)
-120
>>> shortest_rotation(0, 180)
-180
>>> shortest_rotation(0, 181)
-179
>>> shortest_rotation(0, 179)
179
>>> shortest_rotation(10, 350)
-20
You can now create a list of angles, turning in the shortest direction:
def rotation_steps(start_angle, end_angle, n):
increment = shortest_rotation(start_angle, end_angle) / n
return [(start_angle + i * increment) % 360 for i in range(n + 1)]
As an example:
>>> rotation_steps(90, 270, 12)
[90.0, 75.0, 60.0, 45.0, 30.0, 15.0, 0.0, 345.0, 330.0, 315.0, 300.0, 285.0, 270.0]
>>> rotation_steps(10, 350, 2)
[10.0, 0.0, 350.0]
The list uses float in order to avoid missing the end_angle
if increment
isn't an integer.
How to enumerate over selected elements from an iterable keeping original indices?
Here my comment as an answer ;)
months = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"]
offset = 5
step = 2
for index, element in enumerate(months[offset::step]):
# recalculate original index
index = offset + index*step
# actually repetition of the month is trivial,
# but I put it just to show that the index is right
print(index, element, months[index])
Prints:
5 June June
7 August August
9 October October
11 December December
How to transform a slice to a list of index in python?
You can use the indices
method of the slice to generate a tuple that can be passed to range
. You need to know the length of your instance though.
For example:
>>> sl = slice(2) # or wherever you get that from
>>> length = 100
>>> list(range(*sl.indices(length)))
[0, 1]
How to slice a list using indexes in another list
Using itertools.pairwise
:
>>> from itertools import pairwise
>>> for i, j in pairwise([0, 888, 1776, 2664, 3551, 4438]):
... print(i, j)
...
0 888
888 1776
1776 2664
2664 3551
3551 4438
What's next? I think you can solve it yourself.
Understanding slicing
The syntax is:
a[start:stop] # items start through stop-1
a[start:] # items start through the rest of the array
a[:stop] # items from the beginning through stop-1
a[:] # a copy of the whole array
There is also the step
value, which can be used with any of the above:
a[start:stop:step] # start through not past stop, by step
The key point to remember is that the :stop
value represents the first value that is not in the selected slice. So, the difference between stop
and start
is the number of elements selected (if step
is 1, the default).
The other feature is that start
or stop
may be a negative number, which means it counts from the end of the array instead of the beginning. So:
a[-1] # last item in the array
a[-2:] # last two items in the array
a[:-2] # everything except the last two items
Similarly, step
may be a negative number:
a[::-1] # all items in the array, reversed
a[1::-1] # the first two items, reversed
a[:-3:-1] # the last two items, reversed
a[-3::-1] # everything except the last two items, reversed
Python is kind to the programmer if there are fewer items than you ask for. For example, if you ask for a[:-2]
and a
only contains one element, you get an empty list instead of an error. Sometimes you would prefer the error, so you have to be aware that this may happen.
Relationship with the slice
object
A slice
object can represent a slicing operation, i.e.:
a[start:stop:step]
is equivalent to:
a[slice(start, stop, step)]
Slice objects also behave slightly differently depending on the number of arguments, similarly to range()
, i.e. both slice(stop)
and slice(start, stop[, step])
are supported.
To skip specifying a given argument, one might use None
, so that e.g. a[start:]
is equivalent to a[slice(start, None)]
or a[::-1]
is equivalent to a[slice(None, None, -1)]
.
While the :
-based notation is very helpful for simple slicing, the explicit use of slice()
objects simplifies the programmatic generation of slicing.
Related Topics
Local Notification While App Not Running
How to Link Xctest Dependency to Production/Main Target
Get Location from Center of Screen Swift Mapkit
Wait Until an Asynchronous API Call Is Completed - Swift/Ios
Need to Check That Braces in Given Array Are Balanced or Not
How to Change Colour of the Certain Words in Label - Swift 3
Converting .M4A File to .Aiff Using Audioconverter Swift
How to Convert a Swift String to Cfstring
Swift Codable Decode Manually Optional Variable
(Swift) Nstimer Stop When Scrolling
Swift Realm, Load the Pre-Populated Database the Right Way
Include an Extension for a Class Only If iOS11 Is Available
Rxswift/Rxcocoa: Prevent Uitextfield from Having More Than ... Characters
How to Use Image Literal in Xcode 13