4
\$\begingroup\$

What it does

Calculates the mean difference for a list of any combination of ints (I think).

What I want to know

The only other way I can think of doing this is using recursion.

I’d like to know if there are other better ways to do this.

Also the reason I done this is because I wanted to calculate the mean difference between time stamps I have in another script, so used this as an exercise, that one will be more difficult since it’s 24 hr time, when it gets to the part of switching from:

12:00 -> 00:00

Code:

nums = [3, 1, 2, 5, 1, 5, -7, 9, -8, -3, 3]

l = len(nums) - 1

diff_list = []

for i in range(l):
    diff = nums[0] - nums[1]
    if diff < 0:
        diff = nums[1] - nums[0]
    diff_list.append(diff)
    nums.pop(0)

mean = sum(diff_list)/len(diff_list)

print(round(mean, 1))
\$\endgroup\$
2
  • \$\begingroup\$ I would advice you against using list comprehensions for timestamps. Time can be a tricky thing to deal with, timezones, leap years, leap seconds. Etc. Again a quick google search, should head you in the direction of always using datetime when dealing with time. Feel free to post a follow up question if you want further comments on your particular implementation \$\endgroup\$ Jun 8, 2021 at 8:59
  • \$\begingroup\$ Thank you, I think I will once I get going with it, you’ve been very helpful thanks :) \$\endgroup\$
    – Nickotine
    Jun 8, 2021 at 10:51

2 Answers 2

4
\$\begingroup\$

Reinventing the wheel

Now I will try not to sound too harsh, but did you attempt to google the problem at hand before starting? Building habits in programming is important, but it is equally important to building upon existing code. A quck search gives me the following useful links here, here and here.

General comments

l = len(nums) - 1

This needs a better name. A good rule of thumb is to avoid single letter variables. Secondly this variable is only used once, and thus is not needed. As you could have done

for i in range(len(nums)-1):

which is just as clear. As mentioned the next part could be shortened to

diff = abs(nums[0] - nums[1])

Perhaps the biggest woopsie in your code is nums.pop(0) for two reasons

  1. It modifies your original list. Assume you have calculated and the mean differences, but now want to access the first element in your list: nums[0] what happens?
  2. Secondly pop is an expensive operation, as it shifts the indices for every element in the list for every pop.

Luckily we are iterating over the indices so we can use them to avoid poping. Combining we get

for i in range(len(nums) - 1):
    diff = abs(nums[i-1] - nums[i])
    diff_list.append(diff)

However, this can be written in a single line if wanted as other answers have shown. zip is another solution for a simple oneliner, albeit it should be slightly slower due to slicing. I do not know how important performance is to you, so zip might be fine

[abs(j - i) for i, j in zip(nums, nums[1:])]

If speed is important it could be worth checking out numpy

Improvements

Combining everything, adding hints and struct and a numpy version we get

import numpy as np
from typing import List


def element_difference_1(nums: List[int]) -> List[int]:
    return [abs(j - i) for i, j in zip(nums, nums[1:])]


def element_difference_2(nums: List[int]) -> List[int]:
    return [abs(nums[i + 1] - nums[i]) for i in range(len(nums) - 1)]


def mean_value(lst: List[int]) -> float:
    return sum(lst) / len(lst)


def mean_difference(nums: List[int], diff_function, rounding: int = 1) -> None:
    num_diffs = diff_function(nums)
    mean = mean_value(num_diffs)
    return round(mean, rounding)


def mean_difference_np(lst) -> float:
    return np.mean(np.abs(np.diff(lst)))


if __name__ == "__main__":
    nums = [3, 1, 2, 5, 1, 5, -7, 9, -8, -3, 3]
    print(mean_difference(nums, element_difference_1))
    print(mean_difference(nums, element_difference_2))
    print(mean_difference_np(np.array(nums)))
\$\endgroup\$
2
  • \$\begingroup\$ Thank you, I wanted this to be list comprehensions (got a bunch from you) as I’m getting bored of for loops I like your approach, they should’ve just made python a strictly typed language I’m seeing everyone importing from typing these days. I didn’t google it heh heh I was just practicing in preparation for finding the difference between my timestamp script, didn’t know pop was expensive thanks for the heads up, the list is disposable, that’s why I wasn’t worried about messing it up :) \$\endgroup\$
    – Nickotine
    Jun 8, 2021 at 8:25
  • \$\begingroup\$ Thanks for going through all that with me I’ll keep this and learn from it \$\endgroup\$
    – Nickotine
    Jun 8, 2021 at 9:02
4
\$\begingroup\$

You can reduce a lot of your code just by using pythons builtin abs function. I also used list comprehension to shorted your code, so your entire loop code is now in one line.

This also looks like a great candidate for a function. Now, you can pass any collection of numbers to the function, allowing you to reuse this code however many times you want.

from typing import List

def mean_difference(nums: List[int]) -> None:
    diff_list = [abs(nums[i] - nums[i + 1]) for i in range(len(nums) - 1)]
    mean = sum(diff_list) / len(diff_list)
    return round(mean, 1)
\$\endgroup\$
1
  • \$\begingroup\$ Thanks a lot I really wanted to use list comprehension for this one, but got stuck with annoying old for, this is really nice \$\endgroup\$
    – Nickotine
    Jun 8, 2021 at 8:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.