Theo dõi số lần một hàm đệ quy được gọi


62

 function singleDigit(num) {
      let counter = 0
      let number = [...num + ''].map(Number).reduce((x, y) => {return x * y})

      if(number <= 9){
          console.log(number)
      }else{
          console.log(number)
          return singleDigit(number), counter += 1
      }
   }
singleDigit(39)

Đoạn mã trên lấy một số nguyên và giảm nó thành một chữ số bằng cách nhân nó với các chữ số của chính nó.

Ví dụ là 39.

3 x 9 = 27.
2 x 7 = 14.
1 x 4 = 4.

Bảng điều khiển sẽ đăng nhập:

27 
14 
4

Làm cách nào để theo dõi hàm đệ quy được gọi 3 lần?

Tôi đã thử thêm một bộ đếm nhưng không cập nhật được. Sẽ đánh giá cao sự giúp đỡ


4
.map(Number)là dư thừa vì *toán tử ép các giá trị thành số nào. ;-)
RobG

4
Một vài câu hỏi: 1) Bạn dự định xử lý các số âm như thế nào? Ví dụ, số -57thực sự là a -50và a -7.. khi nhìn theo cách này, nó sẽ làm giảm -5x -7mang lại một số dương 35. Hoặc bạn có muốn nó chỉ nhìn thấy dấu âm với 5và không 7, thậm chí tho 7thực sự là âm. 2) Làm thế nào để bạn có ý định xử lý các số bao gồm số 0? vì điều này sẽ tự động không giảm. Do đó, số lượng bạn vượt qua càng lớn, càng có nhiều khả năng nó sẽ thoát ra. Tùy chọn khác sẽ là bỏ qua các số không
Pimp Trizkit

3
Tôi nhận ra các câu hỏi trên của tôi không phải là về việc đếm đệ quy, mà chỉ là khía cạnh giải câu đố của nội dung được sử dụng trong câu hỏi này. Xin hãy tha thứ cho tôi.
Pimp Trizkit

3
Tôi rất hãnh diện rằng bạn thích câu trả lời của tôi, nhưng với mục đích thực tế, tôi nghĩ stackoverflow.com/a/59570894/1346276 là biến thể chung sạch nhất.
phipsgabler

2
@phipsgabler bất cứ ai dành thời gian để viết một câu trả lời thông minh và mạch lạc đều xứng đáng được nhận. Cảm ơn bạn
chs242

Câu trả lời:


25

Đây là một biến thể học thuật gần như hoàn toàn, nhưng bạn có thể sử dụng một tổ hợp điểm cố định đã sửa đổi cho mục đích này.

Hãy rút ngắn và cải thiện chức năng ban đầu của bạn một chút:

function singleDigit(n) {
    let digitProduct = [...(n + '')].reduce((x, y) => x * y, 1);
    return digitProduct <= 9 ? digitProduct : singleDigit(digitProduct);
}

// singleDigit(123234234) == 0

Từ biến thể này, chúng ta có thể tạo ra và gọi lại cuộc gọi đệ quy:

function singleDigitF(recur) {
    return function (n) {
        let digitProduct = [...(n + '')].reduce((x, y) => x * y, 1);
        return digitProduct <= 9 ? digitProduct : recur()(digitProduct);
    };
}

Bây giờ chức năng này có thể được sử dụng với bộ kết hợp điểm cố định; cụ thể tôi đã triển khai một bộ kết hợp Y được điều chỉnh cho JavaScript (nghiêm ngặt) như sau:

function Ynormal(f, ...args) {
    let Y = (g) => g(() => Y(g));
    return Y(f)(...args);
}

nơi chúng ta có Ynormal(singleDigitF, 123234234) == 0.

Bây giờ đến mẹo. Vì chúng tôi đã tìm ra đệ quy cho tổ hợp Y, chúng tôi có thể đếm số lần thu hồi trong đó:

function Ycount(f, ...args) {
    let count = 1;
    let Y = (g) => g(() => {count += 1; return Y(g);});
    return [Y(f)(...args), count];
}

Kiểm tra nhanh trong REPL Node cho:

> Ycount(singleDigitF, 123234234)
[ 0, 3 ]
> let digitProduct = (n) => [...(n + '')].reduce((x, y) => x * y, 1)
undefined
> digitProduct(123234234)
3456
> digitProduct(3456)
360
> digitProduct(360)
0
> Ycount(singleDigitF, 39)
[ 4, 3 ]

Bộ kết hợp này bây giờ sẽ hoạt động để đếm số lượng cuộc gọi trong bất kỳ chức năng đệ quy nào được viết theo kiểu singleDigitF.

(Lưu ý rằng có hai nguồn nhận được không như một câu trả lời rất thường xuyên: tràn số ( 123345456999999999trở 123345457000000000. Vv), và thực tế là bạn gần như chắc chắn sẽ nhận được không như một đâu đó giá trị trung gian, khi kích thước của đầu vào đang tăng trưởng)


6
Đối với những người downvoters: Tôi thực sự đồng ý với bạn rằng đây không phải là giải pháp thực tế tốt nhất - đó là lý do tại sao tôi đặt tiền tố là "hoàn toàn học thuật".
phipsgabler

Thành thật mà nói, đó là một giải pháp tuyệt vời và hoàn toàn phù hợp với kiểu hồi quy / toán học của câu hỏi ban đầu.
Sheraff

73

Bạn nên thêm một đối số truy cập vào định nghĩa hàm của bạn:

function singleDigit(num, counter = 0) {
    console.log(`called ${counter} times`)
    //...
    return singleDigit(number, counter+1)
}
singleDigit(39)

6
tuyệt vời. Có vẻ như bộ đếm của tôi không hoạt động vì tôi đã khai báo nó trong hàm
chs242

7
@ chs242 quy tắc phạm vi sẽ ra lệnh rằng việc khai báo nó trong hàm sẽ tạo ra một quy tắc mới cho mỗi lần gọi. stackoverflow.com/questions/500431/
trộm

10
@ chs242 không phải là bạn đã khai báo nó trong hàm. Về mặt kỹ thuật, tất cả các tham số mặc định cũng đang hoạt động - trong trường hợp của bạn, đơn giản là giá trị không bao giờ được chuyển sang lần tiếp theo khi hàm được gọi đệ quy. ae mỗi khi chức năng chạy countersẽ bị loại bỏ và được đặt thành 0, trừ khi bạn rõ ràng thực hiện nó trong cuộc gọi đệ quy như Sheraff. AesingleDigit(number, ++counter)
zfrisch

2
đúng @zfrisch Tôi hiểu điều đó bây giờ. Cảm ơn bạn đã dành thời gian để giải thích nó
chs242

35
Hãy đổi ++countersang counter+1. Chúng tương đương về mặt chức năng, nhưng cái sau chỉ định ý định tốt hơn, không (không cần thiết) đột biến và tham số, và không có khả năng vô tình tăng sau. Hoặc tốt hơn, vì đó là một cuộc gọi đuôi, thay vào đó hãy sử dụng một vòng lặp.
BlueRaja - Daniel Pflughoeft

37

Giải pháp truyền thống là truyền số đếm dưới dạng tham số cho hàm theo gợi ý của câu trả lời khác.

Tuy nhiên, có một giải pháp khác trong js. Một vài câu trả lời khác được đề xuất chỉ đơn giản là khai báo đếm ngoài hàm đệ quy:

let counter = 0
function singleDigit(num) {
  counter++;
  // ..
}

Điều này tất nhiên hoạt động. Tuy nhiên, điều này làm cho hàm không reentrant (không thể được gọi chính xác hai lần). Trong một số trường hợp, bạn có thể bỏ qua vấn đề này và chỉ cần đảm bảo rằng bạn không gọi singleDigithai lần (javascript là một luồng nên không quá khó để thực hiện) nhưng đây là một lỗi đang chờ xảy ra nếu bạn cập nhật singleDigitsau đó không đồng bộ và nó cũng cảm thấy xấu xí.

Giải pháp là khai báo counterbiến bên ngoài nhưng không phải trên toàn cầu. Điều này là có thể bởi vì javascript đã đóng:

function singleDigit(num) {
  let counter = 0; // outside but in a closure

  // use an inner function as the real recursive function:
  function recursion (num) {
    counter ++
    let number = [...num + ''].map(Number).reduce((x, y) => {return x * y})

    if(number <= 9){
      return counter            // return final count (terminate)
    }else{
      return recursion(number)  // recurse!
    }
  }

  return recursion(num); // start recursion
}

Điều này tương tự như giải pháp toàn cầu nhưng mỗi lần bạn gọi singleDigit(hiện không phải là hàm đệ quy) nó sẽ tạo ra một thể hiện mới của counterbiến.


1
Biến truy cập chỉ khả dụng trong singleDigithàm và cung cấp một cách rõ ràng khác để thực hiện việc này mà không truyền imo đối số. +1
AndrewL64

1
recursionbây giờ hoàn toàn bị cô lập, nó sẽ hoàn toàn an toàn để vượt qua bộ đếm như là tham số cuối cùng. Tôi không nghĩ việc tạo ra một chức năng bên trong là cần thiết. Nếu bạn không thích ý tưởng có các tham số vì lợi ích duy nhất của đệ quy (tôi có quan điểm rằng người dùng có thể gây rối với chúng) thì hãy khóa chúng Function#bindtrong một chức năng được áp dụng một phần.
customcommander

@customcommander Vâng, tôi đã đề cập đến điều này trong phần đầu tiên của câu trả lời của tôi - the traditional solution is to pass the count as a parameter. Đây là một giải pháp thay thế trong một ngôn ngữ đã đóng cửa. Theo một số cách, nó đơn giản hơn để làm theo bởi vì nó chỉ là một biến thay vì số lượng các trường hợp biến có thể vô hạn. Theo những cách khác, việc biết giải pháp này sẽ giúp ích khi thứ bạn đang theo dõi là một đối tượng được chia sẻ (hãy tưởng tượng xây dựng một bản đồ duy nhất) hoặc một đối tượng rất lớn (chẳng hạn như chuỗi HTML)
slebetman

counter--sẽ là cách truyền thống để giải quyết yêu cầu của bạn về "không thể được gọi chính xác hai lần"
MonkeyZeus

1
@MonkeyZeus Điều đó có gì khác biệt? Ngoài ra, làm thế nào bạn biết số nào để khởi tạo bộ đếm để thấy rằng đó là số mà chúng tôi muốn tìm?
slebetman

22

Một cách tiếp cận khác, vì bạn sản xuất tất cả các số, là sử dụng một trình tạo.

Phần tử cuối cùng là số của bạn ngiảm xuống một số có một chữ số và để đếm số lần bạn đã lặp, chỉ cần đọc độ dài của mảng.

const digits = [...to_single_digit(39)];
console.log(digits);
//=> [27, 14, 4]
<script>
function* to_single_digit(n) {
  do {
    n = [...String(n)].reduce((x, y) => x * y);
    yield n;
  } while (n > 9);
}
</script>


Suy nghĩ cuối cùng

Bạn có thể muốn xem xét có một điều kiện trở lại sớm trong chức năng của bạn. Bất kỳ số nào có số 0 trong đó sẽ trả về số không.

singleDigit(1024);       //=> 0
singleDigit(9876543210); //=> 0

// possible solution: String(n).includes('0')

Điều tương tự có thể được nói cho bất kỳ số nào được làm bằng 1chỉ.

singleDigit(11);    //=> 1
singleDigit(111);   //=> 1
singleDigit(11111); //=> 1

// possible solution: [...String(n)].every(n => n === '1')

Cuối cùng, bạn đã không làm rõ liệu bạn chỉ chấp nhận số nguyên dương. Nếu bạn chấp nhận số nguyên âm thì việc chuyển chúng thành chuỗi thể gặp rủi ro:

[...String(39)].reduce((x, y) => x * y)
//=> 27

[...String(-39)].reduce((x, y) => x * y)
//=> NaN

Giải pháp có thể:

const mult = n =>
  [...String(Math.abs(n))].reduce((x, y) => x * y, n < 0 ? -1 : 1)

mult(39)
//=> 27

mult(-39)
//=> -27

tuyệt quá. @customcommander cảm ơn bạn đã giải thích điều này rất rõ ràng
chs242

6

Đã có nhiều câu trả lời thú vị ở đây. Tôi nghĩ rằng phiên bản của tôi cung cấp một thay thế thú vị bổ sung.

Bạn làm một số điều với chức năng cần thiết của bạn. Bạn đệ quy giảm nó xuống một chữ số. Bạn ghi nhật ký các giá trị trung gian và bạn muốn có một số lượng các cuộc gọi đệ quy được thực hiện. Một cách để xử lý tất cả điều này là viết một hàm thuần sẽ trả về cấu trúc dữ liệu chứa kết quả cuối cùng, các bước được thực hiện và tổng số cuộc gọi được tính trong một:

  {
    digit: 4,
    steps: [39, 27, 14, 4],
    calls: 3
  }

Sau đó, bạn có thể đăng nhập các bước nếu bạn muốn hoặc lưu trữ chúng để xử lý thêm.

Đây là một phiên bản thực hiện điều đó:

const singleDigit = (n, steps = []) =>
  n <= 9
    ? {digit: n, steps: [... steps, n], calls: steps .length}
    : singleDigit ([... (n + '')] .reduce ((a, b) => a * b), [... steps, n])

console .log (singleDigit (39))

Lưu ý rằng chúng tôi theo dõi stepsnhưng xuất phát từ calls. Mặc dù chúng tôi có thể theo dõi số lượng cuộc gọi với một tham số bổ sung, nhưng điều đó dường như không thu được gì. Chúng tôi cũng bỏ qua map(Number)bước này - chúng sẽ được ép thành số trong mọi trường hợp bằng cách nhân.

Nếu bạn lo ngại về stepstham số mặc định đó bị lộ như một phần của API, thì đủ dễ để che giấu nó bằng cách sử dụng một hàm nội bộ như thế này:

const singleDigit = (n) => {
  const recur = (n, steps) => 
    n <= 9
      ? {digit: n, steps: [... steps, n], calls: steps .length}
      : recur ([... (n + '')] .reduce ((a, b) => a * b), [... steps, n])
  return recur (n, [])
}

Và trong cả hai trường hợp, có thể sạch hơn một chút để trích xuất phép nhân chữ số thành hàm trợ giúp:

const digitProduct = (n) => [... (n + '')] .reduce ((a, b) => a * b)

const singleDigit = (n, steps = []) =>
  n <= 9
    ? {digit: n, steps: [... steps, n], calls: steps .length}
    : singleDigit (digitProduct(n), [... steps, n])

2
Một câu trả lời tuyệt vời khác;) Xin lưu ý rằng khi n âm, digitProductsẽ trả về NaN( -39 ~> ('-' * '3') * '9'). Vì vậy, bạn có thể muốn sử dụng một giá trị tuyệt đối của n và sử dụng -1hoặc 1làm giá trị ban đầu của mức giảm của bạn.
customcommander

@customcommander: thực sự, nó sẽ trở lại {"digit":-39,"steps":[-39],"calls":0}, kể từ đó -39 < 9. Trong khi tôi đồng ý rằng điều này có thể làm với một số kiểm tra lỗi: tham số có phải là số không? - nó có phải là số nguyên dương không? - vv Tôi không nghĩ rằng tôi sẽ cập nhật để bao gồm điều đó. Cái này nắm bắt được thuật toán và việc xử lý lỗi thường đặc trưng cho cơ sở mã của một người.
Scott Sauyet

6

Nếu bạn chỉ đang cố gắng đếm xem nó đã giảm bao nhiêu lần và không quan tâm đến đệ quy một cách cụ thể ... bạn có thể loại bỏ đệ quy. Mã dưới đây vẫn trung thành với Bài đăng gốc vì nó không được tính num <= 9là cần giảm. Do đó, singleDigit(8)sẽ có count = 0, và singleDigit(39)sẽ có count = 3, giống như OP và câu trả lời được chấp nhận đang thể hiện:

const singleDigit = (num) => {
    let count = 0, ret, x;
    while (num > 9) {
        ret = 1;
        while (num > 9) {
            x = num % 10;
            num = (num - x) / 10;
            ret *= x;
        }
        num *= ret;
        count++;
        console.log(num);
    }
    console.log("Answer = " + num + ", count = " + count);
    return num;
}

Không cần thiết phải xử lý số 9 hoặc ít hơn (ví dụ. num <= 9). Thật không may, mã OP sẽ xử lý num <= 9ngay cả khi nó không được tính. Các mã ở trên sẽ không xử lý cũng không tính num <= 9, tất cả. Nó chỉ vượt qua nó thông qua.

Tôi chọn không sử dụng .reducevì làm toán thực tế nhanh hơn nhiều để thực hiện. Và, đối với tôi, dễ hiểu hơn.


Suy nghĩ thêm về tốc độ

Tôi cảm thấy mã tốt cũng nhanh. Nếu bạn đang sử dụng loại giảm này (được sử dụng trong số học rất nhiều), bạn có thể cần phải sử dụng nó trên một lượng lớn dữ liệu. Trong trường hợp này, tốc độ sẽ trở thành tối quan trọng.

Sử dụng cả hai .map(Number)console.log(ở mỗi bước giảm) đều rất dài để thực hiện và không cần thiết. Chỉ cần xóa .map(Number)khỏi OP đã tăng tốc khoảng 4,38 lần. Việc xóa console.lognó đã tăng tốc đến mức gần như không thể kiểm tra đúng cách (tôi không muốn chờ đợi nó).

Vì vậy, tương tự như câu trả lời của customcommander , không sử dụng .map(Number)cũng không console.logvà đẩy kết quả vào một mảng và sử dụng .lengthcho countnhanh hơn nhiều. Thật không may cho câu trả lời của customcommander , sử dụng chức năng trình tạo thực sự rất chậm (câu trả lời đó chậm hơn khoảng 2,68 lần so với OP không có .map(Number)console.log)

Ngoài ra, thay vì sử dụng .reducetôi chỉ sử dụng toán học thực tế. Chỉ riêng sự thay đổi này đã tăng tốc phiên bản chức năng của tôi lên gấp 3,5 lần.

Cuối cùng, đệ quy chậm hơn, nó chiếm không gian ngăn xếp, sử dụng nhiều bộ nhớ hơn và có giới hạn về số lần nó có thể "tái diễn". Hoặc, trong trường hợp này, có thể sử dụng bao nhiêu bước giảm để hoàn thành việc giảm toàn bộ. Đưa ra đệ quy của bạn cho các vòng lặp lặp giữ tất cả trên cùng một vị trí trên ngăn xếp và không có giới hạn lý thuyết về số lượng bước giảm có thể sử dụng để hoàn thành. Do đó, các hàm này ở đây có thể "giảm" hầu hết mọi số nguyên có kích thước, chỉ bị giới hạn bởi thời gian thực hiện và thời gian của một mảng có thể là bao lâu.

Tất cả điều này trong tâm trí ...

const singleDigit2 = (num) => {
    let red, x, arr = [];
    do {
        red = 1;
        while (num > 9) {
            x = num % 10;
            num = (num - x) / 10;
            red *= x;
        }
        num *= red;
        arr.push(num);
    } while (num > 9);
    return arr;
}

let ans = singleDigit2(39);
console.log("singleDigit2(39) = [" + ans + "],  count = " + ans.length );
 // Output: singleDigit2(39) = [27,14,4],  count = 3

Chức năng trên chạy cực nhanh. Nó nhanh hơn khoảng 3,13 lần so với OP (không có .map(Number)console.log) và nhanh hơn khoảng 8.4 lần so với câu trả lời của customcommander . Hãy nhớ rằng việc xóa console.logkhỏi OP sẽ ngăn không cho nó tạo ra một số ở mỗi bước giảm. Do đó, cần phải đẩy các kết quả này thành một mảng.

PT


1
Có rất nhiều giá trị giáo dục trong câu trả lời này vì vậy cảm ơn vì điều đó. I feel good code is also fast.Tôi muốn nói rằng chất lượng mã đã được đo dựa trên một bộ được xác định trước các yêu cầu. Nếu hiệu suất không phải là một trong số đó thì bạn chẳng đạt được gì bằng cách thay thế mã mà bất kỳ ai cũng có thể hiểu bằng mã "nhanh". Bạn sẽ không tin rằng số lượng mã mà tôi đã thấy đã được tái cấu trúc để có hiệu suất đến mức không ai có thể hiểu được mã này nữa (vì một số lý do, mã tối ưu có xu hướng cũng không được ghi nhận;). Cuối cùng hãy lưu ý rằng các danh sách được tạo ra lười biếng cho phép một người tiêu thụ các mặt hàng theo yêu cầu.
customcommander

Cảm ơn bạn, tôi nghĩ. IMHO, đọc toán học thực tế về cách làm nó dễ hiểu đối với tôi hơn là những câu [...num+''].map(Number).reduce((x,y)=> {return x*y})thậm chí hoặc [...String(num)].reduce((x,y)=>x*y)tôi thấy trong hầu hết các câu trả lời ở đây. Vì vậy, với tôi, điều này có thêm lợi ích là hiểu rõ hơn về những gì đang diễn ra ở mỗi lần lặp nhanh hơn nhiều. Có, mã rút gọn (có vị trí của nó) rất khó đọc. Nhưng trong những trường hợp đó, người ta thường không quan tâm đến khả năng đọc của nó mà chỉ là kết quả cuối cùng để cắt và dán và tiếp tục.
Pimp Trizkit

Không JavaScript có phân chia số nguyên để bạn có thể làm tương đương với C digit = num%10; num /= 10;? Trước num - xtiên phải xóa chữ số trước khi chia có khả năng buộc trình biên dịch JIT thực hiện một phân chia riêng biệt với phần tử đã làm để lấy phần còn lại.
Peter Cordes

Tôi không nghĩ vậy. Đây là vars (JS không có ints). Do đó, n /= 10;sẽ chuyển đổi nthành một float nếu cần thiết. num = num/10 - x/10có thể chuyển đổi nó thành một float, đó là dạng dài của phương trình. Do đó, tôi phải sử dụng phiên bản được cấu trúc lại num = (num-x)/10;để giữ cho nó là một số nguyên. Không có cách nào tôi có thể tìm thấy trong JavaScript có thể cung cấp cho bạn cả thương số và phần còn lại của một hoạt động phân chia duy nhất. Ngoài ra, digit = num%10; num /= 10;là hai tuyên bố riêng biệt và do đó hai hoạt động phân chia riêng biệt. Đã một thời gian kể từ khi tôi sử dụng C, nhưng tôi nghĩ rằng điều đó cũng đúng ở đó.
Pimp Trizkit

6

Tại sao không thực hiện một cuộc gọi đến console.counttrong chức năng của bạn?

Chỉnh sửa: Đoạn trích để thử trong trình duyệt của bạn:

function singleDigit(num) {
    console.count("singleDigit");

    let counter = 0
    let number = [...num + ''].map(Number).reduce((x, y) => {return x * y})

    if(number <= 9){
        console.log(number)
    }else{
        console.log(number)
        return singleDigit(number), counter += 1
    }
}
singleDigit(39)

Tôi có nó hoạt động trong Chrome 79 và Firefox 72


console.count sẽ không giúp ích khi bộ đếm được thiết lập lại mỗi khi hàm được gọi (như đã được khám phá trong các câu trả lời ở trên)
chs242

2
Tôi không hiểu vấn đề của bạn khi tôi làm việc với Chrome và Firefox, tôi đã thêm một đoạn trong câu trả lời của mình
Mistermatt

6

Bạn có thể sử dụng đóng cửa cho việc này.

Chỉ đơn giản là lưu trữ countervào các chức năng đóng cửa.

Đây là ví dụ:

function singleDigitDecorator() {
	let counter = 0;

	return function singleDigitWork(num, isCalledRecursively) {

		// Reset if called with new params 
		if (!isCalledRecursively) {
			counter = 0;
		}

		counter++; // *

		console.log(`called ${counter} times`);

		let number = [...(num + "")].map(Number).reduce((x, y) => {
			return x * y;
		});

		if (number <= 9) {
			console.log(number);
		} else {
			console.log(number);

			return singleDigitWork(number, true);
		}
	};
}

const singleDigit = singleDigitDecorator();

singleDigit(39);

console.log('`===========`');

singleDigit(44);


1
Nhưng theo cách này, bộ đếm tiếp tục đếm vào cuộc gọi tiếp theo, nó cần được đặt lại trên mỗi cuộc gọi ban đầu. Nó dẫn đến một câu hỏi khó: làm thế nào để biết khi nào một hàm đệ quy được gọi từ một bối cảnh khác, trong trường hợp này là toàn cục vs hàm.
RobG

Đây chỉ là ví dụ để đưa ra một ý nghĩ. Nó có thể được sửa đổi bằng cách hỏi người dùng về nhu cầu của anh ta.
Kholiavko

@RobG Tôi không hiểu câu hỏi của bạn. Hàm đệ quy không thể được gọi bên ngoài bao đóng vì đây là hàm bên trong. Vì vậy, không có khả năng hoặc cần phân biệt bối cảnh vì chỉ có một bối cảnh có thể xảy ra
slebetman

@slebetman Bộ đếm không bao giờ được đặt lại. Hàm được trả về bởi singleDigitDecorator()sẽ tiếp tục tăng cùng một bộ đếm mỗi lần nó được gọi.
customcommander

1
@ slebetman Vấn đề là chức năng được trả về bởi singleDigitDecorator không thiết lập lại bộ đếm của nó khi nó được gọi lại. Đó là chức năng cần biết khi nào cần thiết lập lại bộ đếm, nếu không thì cần có một phiên bản mới của chức năng cho mỗi lần sử dụng. Một trường hợp sử dụng có thể cho Function.caller ? ;-)
RobG

1

Đây là phiên bản Python sử dụng chức năng bao bọc để đơn giản hóa bộ đếm, như đã được đề xuất bởi câu trả lời của slebetman - Tôi chỉ viết điều này vì ý tưởng cốt lõi rất rõ ràng trong việc triển khai này:

from functools import reduce

def single_digit(n: int) -> tuple:
    """Take an integer >= 0 and return a tuple of the single-digit product reduction
    and the number of reductions performed."""

    def _single_digit(n, i):
        if n <= 9:
            return n, i
        else:
            digits = (int(d) for d in str(n))
            product = reduce(lambda x, y: x * y, digits)
            return _single_digit(product, i + 1)

    return _single_digit(n, 0)

>>> single_digit(39)
(4, 3)

1
Trong Python, tôi thích cái gì đó như thế này .
phipsgabler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.