1

Lets say I've a list:

A = [
    '15.1 total hours', 
    '121 total mins',
    # And more mixed
] 

How can I convert those from mins to hours? Output should be something like:

A = [
    '15.1 total hours', 
    '2.01 total hours',
    # And more mixed
]

2.01 is converted from 121 total mins. I'm not sure if using regex is gonna help me on it?

Inigo Selwood
  • 822
  • 9
  • 20
Tech
  • 65
  • 7

5 Answers5

0

If I understand the question correctly, you have two possible types of strings in your list elements: "{type: float} total hours" and "{type: float} total minutes". Your code would be:

Assumes: ListA = ["15.1 total hours", "121 total mins"]

ListB = []
for element in ListA:
    i = element.split(" ")
    if i[2] == "hours":
        ListB.append(f"{float(i[0])} {i[1]} {i[2]}")
    elif i[2] == "mins":
        ListB.append(f"{float(i[0])/60} {i[1]} {i[2]}")

You can extend this logic (for secs, days, etc) using more elifs.

0

Assuming the all string have the same format and only hours or mins allowed, this should work:

A = ['15.1 total hours', '121 total mins', '366 total mins']

for i, s in enumerate(A):
  elem = s.split()
  if elem[-1] == 'mins':
     mins_value = int(elem[0])
     converted = int(mins_value / 60) + (mins_value % 60) / 100
     A[i] = '{} total hours'.format(converted)

Note that this code will change your array in place.

ma4strong
  • 300
  • 2
  • 8
0

Here's a way to do what you've asked, assuming you want 2 decimals of precision on values converted from minutes to hours, which would match the format of the sample output in your question:

import re
A = ['15.1 total hours', '121 total mins', '7.1 total hours', '101 total mins']
B = []
for a in A:
    m = re.search('([0-9]*\.?[0-9]*).*(hours|mins)', a)
    value, unit = m.groups()
    if unit == 'mins':
        hourValue = float(value) / 60
        a = a.replace(value, f"{hourValue:.2f}")
        a = a.replace('mins', 'hours')
    B.append(a)
A[:] = B
print(A)

Output:

['15.1 total hours', '2.02 total hours', '7.1 total hours', '1.68 total hours']

What we do is to search for a number ([0-9]*\.?[0-9]*) which we save as a regular expression group (thanks to the parentheses) followed by 0 or more characters .* followed by a second group (hours|mins) which is either hours or mins. We then check if it's mins, in which case we (1) convert the value from str to a float and divide by 60 to convert units from minutes to hours and (2) replace the original value with the new one at 2 decimals precision using f"{hourValue:.2f}" and replace mins with hours without changing anything else in the string.

constantstranger
  • 9,176
  • 2
  • 5
  • 19
  • There's no need to match the whole string, why are you replacing instead of of overwriting, and the array subscript `[:]` is redundant – Inigo Selwood May 04 '22 at 08:23
  • @Inigo Selwood the `[:]` subscript does something different from simple assignment, ensuring that any code that may be relying on the object referenced by the variable `A` (for example, in a calling function) will still work, since `[:]` actually updates that object. You can learn about this in [Mutable Sequence Types](https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types) in the Python docs (search for `s[i:j] = t`). – constantstranger May 04 '22 at 12:12
  • @Inigo Selwood Regarding the need to "match the whole string", I'm not sure what you're objecting to; my answer gives the specified result in a readable way, especially given that the regex pattern itself makes it clear that we are focused on whether the string contains 'hours' or 'mins' via `(hours|mins)`. Can you articulate what is wrong with my matching strategy, or are you just voicing your opinion about how best to answer the question (which arguably you have already expressed through your own posted answer)? – constantstranger May 04 '22 at 12:14
  • what you're saying about list mutability is correct, I'm just saying it's redundant. Why bother reassign-copying the object at all. Similarly, there's nothing wrong with matching the whole string, there's just no need. – Inigo Selwood May 04 '22 at 12:57
  • I'm interested you mentioned my answer; I'm nitpicking precisely because other than these two additions discussed above, yours seems identical to the one I'd already offered – Inigo Selwood May 04 '22 at 12:59
  • @Inigo Selwood Please take a closer look. Our answers share the use of `re.search()`, an obvious part of a solution to OP's question, as well as looping over the input list and the use of division to convert from minutes to hours. Further, my use of `re.search()` is somewhat different from yours in that I have used the sequence returned by the `groups()` method to obtain the number string as well as the units string. None of this is rocket science, and neither of us can claim 'prior art' on the use of `re.search()`, looping or floating point division. – constantstranger May 04 '22 at 13:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/244466/discussion-between-inigo-selwood-and-constantstranger). – Inigo Selwood May 04 '22 at 13:13
-1

Your question isn't entirely clear. I'm making 3 assumptions:

  1. The number is always the first thing in the string
  2. Strings are always in the form [number] total (hours|minutes)
  3. Minutes are always integers
import re


hours_list = []
for string in mixed_list:

    # Don't reformat if the units aren't in minutes
    if 'mins' not in string:
        hours_list.append(string)
        continue

    # Match the integer at the start
    minutes = re.search(r'\d+', string).group()
    stub = string[len(minutes):]

    # Convert the minutes to hours, and emplace it back into the string
    hours = int(minutes) / 60
    hours_list.append(f'{hours} total hours')
    
Inigo Selwood
  • 822
  • 9
  • 20
-1
A = ["15.1 total hours", "121 total mins", "20 total mins"]
B = []

for el in A:
    spl = el.split()
    if spl[-1] == 'mins':
        B.append(f"{int(spl[0])/60:.1f} total hours")
    else:
        B.append(el)

Assuming A is in the format above this would be a simple solution

thomas
  • 104
  • 4
  • It's [not advisable](https://stackoverflow.com/questions/1637807/modifying-list-while-iterating) to alter a list while iterating. Also, consider using [f-strings](https://realpython.com/python-f-strings/) rather than formatting – Inigo Selwood May 03 '22 at 16:52
  • 1
    @InigoSelwood edited answer to take suggestions into account – thomas May 03 '22 at 17:08