Explore all Functional Programming open source software, libraries, packages, source code, cloud functions and APIs.

Popular New Releases in Functional Programming

ramda

v0.28.0

mostly-adequate-guide

c5844c2

scala

Scala 2.13.8

fantasy-land

Version 5.0.0

fp-ts

2.11.10

Popular Libraries in Functional Programming

ramda

by ramda doticonjavascriptdoticon

star image 21915 doticonMIT

:ram: Practical functional Javascript

mostly-adequate-guide

by MostlyAdequate doticonjavascriptdoticon

star image 20991 doticonNOASSERTION

Mostly adequate guide to FP (in javascript)

scala

by scala doticonscaladoticon

star image 13628 doticonApache-2.0

Scala 2 compiler and standard library. For bugs, see scala/bug

guides

by thoughtbot doticonrubydoticon

star image 8955 doticon

A guide for programming in style.

fantasy-land

by fantasyland doticonjavascriptdoticon

star image 8895 doticonMIT

Specification for interoperability of common algebraic structures in JavaScript

Learning-SICP

by DeathKing doticonrubydoticon

star image 8398 doticon

MIT视频公开课《计算机程序的构造和解释》中文化项目及课程学习资料搜集。

awesomo

by lk-geimfari doticonpythondoticon

star image 7943 doticonNOASSERTION

A list of cool open source projects written in C, C++, Clojure, Lisp, Elixir, Erlang, Elm, Golang, Haskell, JavaScript, Lua, OCaml, Python, R, Ruby, Rust, Scala, etc.

fp-ts

by gcanti doticontypescriptdoticon

star image 7696 doticonMIT

Functional programming in TypeScript

bacon.js

by baconjs doticontypescriptdoticon

star image 6398 doticonMIT

Functional reactive programming library for TypeScript and JavaScript

Trending New libraries in Functional Programming

ts-pattern

by gvergnaud doticontypescriptdoticon

star image 2569 doticonMIT

🎨 The exhaustive Pattern Matching library for TypeScript, with smart type inference.

pancake-frontend

by pancakeswap doticontypescriptdoticon

star image 1679 doticonGPL-3.0

:pancakes: Pancake main features (farms, pools, IFO, lottery, profiles)

monio

by getify doticonjavascriptdoticon

star image 884 doticonMIT

The most powerful IO monad implementation in JS, possibly in any language!

android-startup

by idisfkj doticonkotlindoticon

star image 775 doticonApache-2.0

🔥The Android Startup library provides a straightforward, performant way to initialize components at the application startup. Both library developers and app developers can use Android Startup to streamline startup sequences and explicitly set the order of initialization.

ultimate_rust_crash_course

by CleanCut doticonrustdoticon

star image 554 doticonMIT

Rust Programming Fundamentals - one course to rule them all, one course to find them...

datatype99

by Hirrolot doticoncdoticon

star image 518 doticonMIT

Algebraic data types for C99

metalang99

by Hirrolot doticoncdoticon

star image 432 doticonMIT

Full-blown preprocessor metaprogramming

ts-belt

by mobily doticontypescriptdoticon

star image 392 doticonMIT

🔧 Fast, modern, and practical utility library for FP in TypeScript.

magic-in-ten-mins

by niltok doticonhtmldoticon

star image 363 doticonCC-BY-4.0

十分钟魔法练习

Top Authors in Functional Programming

1

PacktPublishing

27 Libraries

star icon554

2

gcanti

18 Libraries

star icon10630

3

typelevel

17 Libraries

star icon12142

4

alvinj

16 Libraries

star icon93

5

zio

16 Libraries

star icon1624

6

47degrees

15 Libraries

star icon919

7

gvolpe

12 Libraries

star icon509

8

scala-exercises

11 Libraries

star icon3002

9

arrow-kt

11 Libraries

star icon5214

10

ThoughtWorksInc

10 Libraries

star icon602

1

27 Libraries

star icon554

2

18 Libraries

star icon10630

3

17 Libraries

star icon12142

4

16 Libraries

star icon93

5

16 Libraries

star icon1624

6

15 Libraries

star icon919

7

12 Libraries

star icon509

8

11 Libraries

star icon3002

9

11 Libraries

star icon5214

10

10 Libraries

star icon602

Trending Kits in Functional Programming

No Trending Kits are available at this moment for Functional Programming

Trending Discussions on Functional Programming

How do purely functional languages handle index-based algorithms?

Functional Programming: How does one create a new column to a dataframe that contains a multiindex column?

Functional Programming in Kotlin: Counting elements in list by using fold

Are java streams able to lazilly reduce from map/filter conditions?

Two recursive functions and stackoverflow errors in javascript/nodeJs. Understanding the differences

Using '|' (pipe) operator with std::views does not compile

Apply a filter on a multilevel object based on a different object

What is the relationship between monad functions dist and join in Haskell?

How to Log in F# in a functional way using NLog

Idiomatically moving/sorting values from one Vec into another

QUESTION

How do purely functional languages handle index-based algorithms?

Asked 2022-Apr-05 at 12:51

I have been trying to learn about functional programming, but I still struggle with thinking like a functional programmer. One such hangup is how one would implement index-heavy operations which rely strongly on loops/order-of-execution.

For example, consider the following Java code:

1public class Main {
2    public static void main(String[] args) {
3        List<Integer> nums = Arrays.asList(1,2,3,4,5,6,7,8,9);
4        System.out.println("Nums:\t"+ nums);
5        System.out.println("Prefix:\t"+prefixList(nums));
6    }
7  
8    private static List<Integer> prefixList(List<Integer> nums){
9      List<Integer> prefix = new ArrayList<>(nums);
10      for(int i = 1; i < prefix.size(); ++i)
11        prefix.set(i, prefix.get(i) + prefix.get(i-1));
12      return prefix;
13    }
14}
15/*
16System.out: 
17Nums:   [1, 2, 3, 4, 5, 6, 7, 8, 9]
18Prefix: [1, 3, 6, 10, 15, 21, 28, 36, 45]
19*/
20

Here, in the prefixList function, the nums list is first cloned, but then there is the iterative operation performed on it, where the value on index i relies on index i-1 (i.e. order of execution is required). Then this value is returned.

What would this look like in a functional language (Haskell, Lisp, etc.)? I have been learning about monads and think they may be relevant here, but my understanding is still not great.

ANSWER

Answered 2022-Mar-07 at 21:17

This is not an index-heavy operation, in fact you can do this with a one-liner with scanl1 :: (a -> a -> a) -> [a] -> [a]:

1public class Main {
2    public static void main(String[] args) {
3        List<Integer> nums = Arrays.asList(1,2,3,4,5,6,7,8,9);
4        System.out.println("Nums:\t"+ nums);
5        System.out.println("Prefix:\t"+prefixList(nums));
6    }
7  
8    private static List<Integer> prefixList(List<Integer> nums){
9      List<Integer> prefix = new ArrayList<>(nums);
10      for(int i = 1; i < prefix.size(); ++i)
11        prefix.set(i, prefix.get(i) + prefix.get(i-1));
12      return prefix;
13    }
14}
15/*
16System.out: 
17Nums:   [1, 2, 3, 4, 5, 6, 7, 8, 9]
18Prefix: [1, 3, 6, 10, 15, 21, 28, 36, 45]
19*/
20prefixList = scanl1 (+)
21

indeed, for the list of Nums, we get:

1public class Main {
2    public static void main(String[] args) {
3        List<Integer> nums = Arrays.asList(1,2,3,4,5,6,7,8,9);
4        System.out.println("Nums:\t"+ nums);
5        System.out.println("Prefix:\t"+prefixList(nums));
6    }
7  
8    private static List<Integer> prefixList(List<Integer> nums){
9      List<Integer> prefix = new ArrayList<>(nums);
10      for(int i = 1; i < prefix.size(); ++i)
11        prefix.set(i, prefix.get(i) + prefix.get(i-1));
12      return prefix;
13    }
14}
15/*
16System.out: 
17Nums:   [1, 2, 3, 4, 5, 6, 7, 8, 9]
18Prefix: [1, 3, 6, 10, 15, 21, 28, 36, 45]
19*/
20prefixList = scanl1 (+)
21Prelude> prefixList [1 .. 9]
22[1,3,6,10,15,21,28,36,45]
23

scanl1 takes the first item of the original list as initial value for the accumulator, and yields that. Then each time it takes the accumulator and the next item of the given list, and sums these up as new accumulator, and yields the new accumulator value.

Often one does not need indexing, but enumerating over the list is sufficient. Imperative programming languages often work with for loops with indexes, but in many cases these can be replaced by foreach loops that thus do not take the index into account. In Haskell this also often helps to make algorithms more lazy.

If you really need random access lookups, you can work with data structures such as defined in the array and vector packages.

Source https://stackoverflow.com/questions/71387267

QUESTION

Functional Programming: How does one create a new column to a dataframe that contains a multiindex column?

Asked 2022-Jan-28 at 03:46

Suppose the below simplified dataframe. (The actual df is much, much bigger.) How does one assign values to a new column f such that f is a function of another column (e.,g. e)? I'm pretty sure one needs to use apply or map but never done this with a dataframe that has multiindex columns?

1df = pd.DataFrame([[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]])
2df.columns = pd.MultiIndex.from_tuples((("a", "d"), ("a", "e"), ("b", "d"), ("b","e")))
3df
4    a       b
5    d   e   d   e
60   1   2   3   4
71   5   6   7   8
82   9  10  11  12
93  13  14  15  16
10

Desired output:

1df = pd.DataFrame([[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]])
2df.columns = pd.MultiIndex.from_tuples((("a", "d"), ("a", "e"), ("b", "d"), ("b","e")))
3df
4    a       b
5    d   e   d   e
60   1   2   3   4
71   5   6   7   8
82   9  10  11  12
93  13  14  15  16
10    a          b
11    d   e   f  d   e   f
120   1   2   1  3   4   1
131   5   6   1  7   8  -1
142   9  10  -1  11  12 -1
153  13  14  -1  15  16 -1
16

Would like to be able to apply the following lines and assign them to a new column f. Two problems: First, the last line that contains the apply doesn't work but hopefully my intent is clear. Second, I'm unsure how to assign values to a new column of a dataframe with a multi index column structure. Would like to be able use functional programming methods.

1df = pd.DataFrame([[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]])
2df.columns = pd.MultiIndex.from_tuples((("a", "d"), ("a", "e"), ("b", "d"), ("b","e")))
3df
4    a       b
5    d   e   d   e
60   1   2   3   4
71   5   6   7   8
82   9  10  11  12
93  13  14  15  16
10    a          b
11    d   e   f  d   e   f
120   1   2   1  3   4   1
131   5   6   1  7   8  -1
142   9  10  -1  11  12 -1
153  13  14  -1  15  16 -1
16lt = df.loc(axis=1)[:,'e'] < 8
17gt = df.loc(axis=1)[:,'e'] >= 8
18conditions = [lt, gt]
19choices = [1, -1]
20df.loc(axis=1)[:,'f'] = df.loc(axis=1)[:,'e'].apply(np.select(conditions, choices))
21

ANSWER

Answered 2022-Jan-28 at 03:46
1df = pd.DataFrame([[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]])
2df.columns = pd.MultiIndex.from_tuples((("a", "d"), ("a", "e"), ("b", "d"), ("b","e")))
3df
4    a       b
5    d   e   d   e
60   1   2   3   4
71   5   6   7   8
82   9  10  11  12
93  13  14  15  16
10    a          b
11    d   e   f  d   e   f
120   1   2   1  3   4   1
131   5   6   1  7   8  -1
142   9  10  -1  11  12 -1
153  13  14  -1  15  16 -1
16lt = df.loc(axis=1)[:,'e'] < 8
17gt = df.loc(axis=1)[:,'e'] >= 8
18conditions = [lt, gt]
19choices = [1, -1]
20df.loc(axis=1)[:,'f'] = df.loc(axis=1)[:,'e'].apply(np.select(conditions, choices))
21nms = [(i, 'f')for i, j in df.columns if j == 'e']    
22df[nms] = (df.iloc[:, [j == 'e' for i, j in df.columns]] < 8) * 2 - 1
23
24df = df.sort_index(axis=1)
25df
26 a          b       
27    d   e  f   d   e  f
280   1   2  1   3   4  1
291   5   6  1   7   8 -1
302   9  10 -1  11  12 -1
313  13  14 -1  15  16 -1
32

EDIT:

for a custom ordering:

1df = pd.DataFrame([[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]])
2df.columns = pd.MultiIndex.from_tuples((("a", "d"), ("a", "e"), ("b", "d"), ("b","e")))
3df
4    a       b
5    d   e   d   e
60   1   2   3   4
71   5   6   7   8
82   9  10  11  12
93  13  14  15  16
10    a          b
11    d   e   f  d   e   f
120   1   2   1  3   4   1
131   5   6   1  7   8  -1
142   9  10  -1  11  12 -1
153  13  14  -1  15  16 -1
16lt = df.loc(axis=1)[:,'e'] < 8
17gt = df.loc(axis=1)[:,'e'] >= 8
18conditions = [lt, gt]
19choices = [1, -1]
20df.loc(axis=1)[:,'f'] = df.loc(axis=1)[:,'e'].apply(np.select(conditions, choices))
21nms = [(i, 'f')for i, j in df.columns if j == 'e']    
22df[nms] = (df.iloc[:, [j == 'e' for i, j in df.columns]] < 8) * 2 - 1
23
24df = df.sort_index(axis=1)
25df
26 a          b       
27    d   e  f   d   e  f
280   1   2  1   3   4  1
291   5   6  1   7   8 -1
302   9  10 -1  11  12 -1
313  13  14 -1  15  16 -1
32d = {i:j for j, i in enumerate(df.columns.levels[0])}
33df1 = df.loc[:, sorted(df.columns, key = lambda x: d[x[0]])]
34

IF the whole data is in a way symmetric, you could do:

1df = pd.DataFrame([[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]])
2df.columns = pd.MultiIndex.from_tuples((("a", "d"), ("a", "e"), ("b", "d"), ("b","e")))
3df
4    a       b
5    d   e   d   e
60   1   2   3   4
71   5   6   7   8
82   9  10  11  12
93  13  14  15  16
10    a          b
11    d   e   f  d   e   f
120   1   2   1  3   4   1
131   5   6   1  7   8  -1
142   9  10  -1  11  12 -1
153  13  14  -1  15  16 -1
16lt = df.loc(axis=1)[:,'e'] < 8
17gt = df.loc(axis=1)[:,'e'] >= 8
18conditions = [lt, gt]
19choices = [1, -1]
20df.loc(axis=1)[:,'f'] = df.loc(axis=1)[:,'e'].apply(np.select(conditions, choices))
21nms = [(i, 'f')for i, j in df.columns if j == 'e']    
22df[nms] = (df.iloc[:, [j == 'e' for i, j in df.columns]] < 8) * 2 - 1
23
24df = df.sort_index(axis=1)
25df
26 a          b       
27    d   e  f   d   e  f
280   1   2  1   3   4  1
291   5   6  1   7   8 -1
302   9  10 -1  11  12 -1
313  13  14 -1  15  16 -1
32d = {i:j for j, i in enumerate(df.columns.levels[0])}
33df1 = df.loc[:, sorted(df.columns, key = lambda x: d[x[0]])]
34df.stack(0).assign(f = lambda x: 2*(x.e < 8) - 1).stack().unstack([1,2])
35Out[]: 
36    a          b       
37    d   e  f   d   e  f
380   1   2  1   3   4  1
391   5   6  1   7   8 -1
402   9  10 -1  11  12 -1
413  13  14 -1  15  16 -1
42

Source https://stackoverflow.com/questions/70888112

QUESTION

Functional Programming in Kotlin: Counting elements in list by using fold

Asked 2022-Jan-20 at 10:53

I've got the task to write a function using fold (functional programming) to count the number of elements in a list that fulfill the predicate. I was given the function signature fun <A> count(list<A>, predicate: (A) -> Boolean): Int. Fold shall not only be used as iteration, but also generate the return value. So I tried to do this:

1fun &lt;A&gt; count(list: List&lt;A&gt;, predicate: (A) -&gt; Boolean): Int {
2        return list.fold(0) {
3            acc, a -&gt;
4            if (predicate(a)) {
5                return acc + 1
6            }
7
8            return acc
9        }
10    }
11

I wrote a println to check if it works:

1fun &lt;A&gt; count(list: List&lt;A&gt;, predicate: (A) -&gt; Boolean): Int {
2        return list.fold(0) {
3            acc, a -&gt;
4            if (predicate(a)) {
5                return acc + 1
6            }
7
8            return acc
9        }
10    }
11println(count3(listOf (1, -2, 3, 10, -5, 8, 12), { it &gt; 0 &amp;&amp; it &lt; 10 }))
12

However, I got the result 1 instead of 3 on the console and I don't know where the fault is. So, does anyone have an idea where my error is or how I can implement the function instead?

And just to be clear: Fold accumulates a value, starting with the initial value (in this case 0) and applying the operation from left to right to the current accumulator and each element or am I mistaken?

EDIT (I hope it's okay to edit a question instead of asking a new one):

Is it possible to return a whole list instead of just an int? I just found examples returning integers or booleans. What I tried: I've used the same function signature from above. But instead of return an Int, I want to return a list:

1fun &lt;A&gt; count(list: List&lt;A&gt;, predicate: (A) -&gt; Boolean): Int {
2        return list.fold(0) {
3            acc, a -&gt;
4            if (predicate(a)) {
5                return acc + 1
6            }
7
8            return acc
9        }
10    }
11println(count3(listOf (1, -2, 3, 10, -5, 8, 12), { it &gt; 0 &amp;&amp; it &lt; 10 }))
12fun &lt;A&gt; returnList(list: List&lt;A&gt;, predicate: (A) -&gt; Boolean): List&lt;A&gt; {
13        return list.fold(mutableListOf()) {
14            acc, a -&gt;
15            if (predicate(a)) {
16                acc.add(a)
17            } else {
18                acc
19            }
20        }
21    }
22

The problem that I found is that acc.add(a) returns a boolean and not a list, so that the IDE marks it as a mistake. So is there a way to return a list?

Thanks in Advance.

ANSWER

Answered 2022-Jan-19 at 17:06

Try it like this:

1fun &lt;A&gt; count(list: List&lt;A&gt;, predicate: (A) -&gt; Boolean): Int {
2        return list.fold(0) {
3            acc, a -&gt;
4            if (predicate(a)) {
5                return acc + 1
6            }
7
8            return acc
9        }
10    }
11println(count3(listOf (1, -2, 3, 10, -5, 8, 12), { it &gt; 0 &amp;&amp; it &lt; 10 }))
12fun &lt;A&gt; returnList(list: List&lt;A&gt;, predicate: (A) -&gt; Boolean): List&lt;A&gt; {
13        return list.fold(mutableListOf()) {
14            acc, a -&gt;
15            if (predicate(a)) {
16                acc.add(a)
17            } else {
18                acc
19            }
20        }
21    }
22fun &lt;A&gt; count(list: List&lt;A&gt;, predicate: (A) -&gt; Boolean): Int {
23    return list.fold(0) { acc, a -&gt; if (predicate(a)) acc+1 else acc }
24}
25
26fun main(args: Array&lt;String&gt;) {
27    val x = listOf&lt;Int&gt;( 1, -2, 3, 10, -5, 8, 12);
28    println(count(x, { it &gt; 0 &amp;&amp; it &lt; 10 }))
29}
30

Looking at this site made the necessary change clear to me.

Is that form necessary because fold uses tail recursion? Interesting to see what the reason is.

Source https://stackoverflow.com/questions/70770779

QUESTION

Are java streams able to lazilly reduce from map/filter conditions?

Asked 2022-Jan-12 at 09:30

I am using a functional programming style to solve the Leetcode easy question, Count the Number of Consistent Strings. The premise of this question is simple: count the amount of values for which the predicate of "all values are in another set" holds.

I have two approaches, one which I am fairly certain behaves as I want it to, and the other which I am less sure about. Both produce the correct output, but ideally they would stop evaluating other elements after the output is in a final state.


1    public int countConsistentStrings(String allowed, String[] words) {
2        final Set&lt;Character&gt; set = allowed.chars()
3          .mapToObj(c -&gt; (char)c)
4          .collect(Collectors.toCollection(HashSet::new));
5        return (int)Arrays.stream(words)
6          .filter(word -&gt;
7                  word.chars()
8                  .allMatch(c -&gt; set.contains((char)c))
9                 )
10          .count();
11    }
12

In this solution, to the best of my knowledge, the allMatch statement will terminate and evaluate to false at the first instance of c for which the predicate does not hold true, skipping the other values in that stream.


1    public int countConsistentStrings(String allowed, String[] words) {
2        final Set&lt;Character&gt; set = allowed.chars()
3          .mapToObj(c -&gt; (char)c)
4          .collect(Collectors.toCollection(HashSet::new));
5        return (int)Arrays.stream(words)
6          .filter(word -&gt;
7                  word.chars()
8                  .allMatch(c -&gt; set.contains((char)c))
9                 )
10          .count();
11    }
12    public int countConsistentStrings(String allowed, String[] words) {
13        Set&lt;Character&gt; set = allowed.chars()
14          .mapToObj(c -&gt; (char)c)
15          .collect(Collectors.toCollection(HashSet::new));
16        return (int)Arrays.stream(words)
17          .filter(word -&gt;
18                  word.chars()
19                  .mapToObj(c -&gt; set.contains((char)c))
20                  .reduce((a,b) -&gt; a&amp;&amp;b)
21                  .orElse(false)
22                 )
23          .count();
24    }
25

In this solution, the same logic is used but instead of allMatch, I use map and then reduce. Logically, after a single false value comes from the map stage, reduce will always evaluate to false. I know Java streams are lazy, but I am unsure when they ''know'' just how lazy they can be. Will this be less efficient than using allMatch or will laziness ensure the same operation?


Lastly, in this code, we can see that the value for x will always be 0 as after filtering for only positive numbers, the sum of them will always be positive (assume no overflow) so taking the minimum of positive numbers and a hardcoded 0 will be 0. Will the stream be lazy enough to evaluate this to 0 always, or will it work to reduce every element after the filter anyways?

1    public int countConsistentStrings(String allowed, String[] words) {
2        final Set&lt;Character&gt; set = allowed.chars()
3          .mapToObj(c -&gt; (char)c)
4          .collect(Collectors.toCollection(HashSet::new));
5        return (int)Arrays.stream(words)
6          .filter(word -&gt;
7                  word.chars()
8                  .allMatch(c -&gt; set.contains((char)c))
9                 )
10          .count();
11    }
12    public int countConsistentStrings(String allowed, String[] words) {
13        Set&lt;Character&gt; set = allowed.chars()
14          .mapToObj(c -&gt; (char)c)
15          .collect(Collectors.toCollection(HashSet::new));
16        return (int)Arrays.stream(words)
17          .filter(word -&gt;
18                  word.chars()
19                  .mapToObj(c -&gt; set.contains((char)c))
20                  .reduce((a,b) -&gt; a&amp;&amp;b)
21                  .orElse(false)
22                 )
23          .count();
24    }
25List&lt;Integer&gt; list = new ArrayList&lt;&gt;();
26...
27/*Some values added to list*/
28...
29int x = list.stream()
30        .filter(i -&gt; i &gt;= 0)
31        .reduce((a,b) -&gt; Math.min(a+b, 0))
32        .orElse(0);
33

To summarize the above, how does one know when the Java stream will be lazy? There are lazy opportunities that I see in the code, but how can I guarantee that my code will be as lazy as possible?

ANSWER

Answered 2022-Jan-12 at 09:30

The actual term you’re asking for is short-circuiting

Further, some operations are deemed short-circuiting operations. An intermediate operation is short-circuiting if, when presented with infinite input, it may produce a finite stream as a result. A terminal operation is short-circuiting if, when presented with infinite input, it may terminate in finite time. Having a short-circuiting operation in the pipeline is a necessary, but not sufficient, condition for the processing of an infinite stream to terminate normally in finite time.

The term “lazy” only applies to intermediate operations and means that they only perform work when being requested by the terminal operation. This is always the case, so when you don’t chain a terminal operation, no intermediate operation will ever process any element.

Finding out whether a terminal operation is short-circuiting, is rather easy. Go to the Stream API documentation and check whether the particular terminal operation’s documentation contains the sentence

This is a short-circuiting terminal operation.

allMatch has it, reduce has not.

This does not mean that such optimizations based on logic or algebra are impossible. But the responsibility lies at the JVM’s optimizer which might do the same for loops. However, this requires inlining of all involved methods to be sure that this conditions always applies and there are no side effect which must be retained. This behavioral compatibility implies that even if the processing gets optimized away, a peek(System.out::println) would keep printing all elements as if they were processed. In practice, you should not expect such optimizations, as the Stream implementation code is too complex for the optimizer.

Source https://stackoverflow.com/questions/70673795

QUESTION

Two recursive functions and stackoverflow errors in javascript/nodeJs. Understanding the differences

Asked 2022-Jan-04 at 16:54

Looking into the SICP book and JS functional programming I created two recursive functions. My expectation was that both of them raised a stack overflow error. But it is only the sumAll() function that raised the error. See below the code for both functions sumAll() and factorial():

As expected the sumAll() function did raise a stack overflow error

1function sumAll(n, i = 0, result = 0) {
2  return (i &gt; n)
3    ? result
4    : sumAll(n, i + 1, i + result);
5}
6    
7console.log(sumAll(10000));

The factorial() function below did not raise a stack overflow error:

1function sumAll(n, i = 0, result = 0) {
2  return (i &gt; n)
3    ? result
4    : sumAll(n, i + 1, i + result);
5}
6    
7console.log(sumAll(10000));function factorial(n){
8  return (n == 1)
9    ? 1
10    :  n* factorial((n-1))
11}
12    
13console.log(factorial(10000))

My question is why the factorial() function does not raise a stack overflow and works perfectly in nodeJS meanwhile the sumAll() did raise it also in nodeJS

ANSWER

Answered 2022-Jan-03 at 14:42

I gave the below answer in error, I got mixed up about which function was throwing the exception. Please ignore.

Your first function is capable of taking advantage of tail-call optimization, while your second function is not (or it is, but perhaps not in a way that's implemented in the node.js language).

Consider this: your first function's usual condition is that it ends in return sumAll(n, i + 1, i + result), which means that once you get something to return, you can just return that.

Your second function however ends in return n* factorial((n-1)), which means that once you get something to return, you have to do ANOTHER operation on it (multiply it by n) before you can actually return the result.

I believe the node.js interpreter isn't able to tail-call-optimize the second function because it requires another operation to be performed on it before the return.

Please note: I am not certain this is the answer, and I suspect node.js may not support tail call optimizations of any sort. This is my theory though about why one function might error in that way and the other one wouldn't.

Source https://stackoverflow.com/questions/70567315

QUESTION

Using '|' (pipe) operator with std::views does not compile

Asked 2021-Dec-02 at 11:55

After a career diversion, I am trying to get up to speed with std::views (and functional programming in general). I am using the '|' (pipe) operator with std::views::filter on a vector, and I am puzzled why some code structures compile and others don't.

This code creates a vector of vectors of int, then filters them by sum. I've commented the three statements that are confusing me, the first two of which compile and the third doesn't.

Compilation error is:

1'|': no operator found which takes a left-hand operand of type 'std::vector&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;,std::allocator&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;&gt;&gt;' (or there is no acceptable conversion)  
2

(Using MSVC19, compiled with /std:c++latest)

I am puzzled as to why this doesn't compile while (2) especially does?

1'|': no operator found which takes a left-hand operand of type 'std::vector&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;,std::allocator&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;&gt;&gt;' (or there is no acceptable conversion)  
2#include &lt;vector&gt;
3#include &lt;numeric&gt;
4#include &lt;ranges&gt;
5
6template&lt;typename T&gt;
7auto buildMultiples(const std::vector&lt;T&gt;&amp; base)
8{
9    std::vector&lt;std::vector&lt;T&gt;&gt; vRet;
10    for(T n= 1; n &lt;= 5; n++)
11    {
12        auto v = base;
13        for (auto&amp; m : v) m *= n;
14        vRet.push_back(v);
15    }
16    return vRet;
17}
18
19template&lt;typename T&gt;
20struct sumGreaterThan
21{
22    T _limit{ 0 };
23
24    auto operator()(const std::vector&lt;T&gt;&amp; v) {return std::accumulate(v.cbegin(), v.cend(), 0) &gt; _limit;}
25};
26   
27int main()
28{
29    using namespace std;
30    vector&lt;int&gt; nums{1,2,3,4,5,6,7,8,9};
31
32    auto mults = buildMultiples(nums);
33
34    for (auto&amp; m : buildMultiples(nums)) {} //1. Compiles
35
36    sumGreaterThan sumFilter{ 10 };
37    
38    auto vecs = buildMultiples(nums);
39    for (auto&amp; m : vecs | views::filter(sumFilter)) {} //2. Compiles
40
41    for (auto&amp; m : buildMultiples(nums) | views::filter(sumFilter)) {} //3. Compilation Error!!
42
43    for (auto vecs = buildMultiples(nums); auto &amp; m : vecs | views::filter(sumFilter)) {} // 4. Compiles. Thanks @Aryter
44}
45

ANSWER

Answered 2021-Dec-01 at 22:04

This is passing an lvalue vector into filter:

1'|': no operator found which takes a left-hand operand of type 'std::vector&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;,std::allocator&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;&gt;&gt;' (or there is no acceptable conversion)  
2#include &lt;vector&gt;
3#include &lt;numeric&gt;
4#include &lt;ranges&gt;
5
6template&lt;typename T&gt;
7auto buildMultiples(const std::vector&lt;T&gt;&amp; base)
8{
9    std::vector&lt;std::vector&lt;T&gt;&gt; vRet;
10    for(T n= 1; n &lt;= 5; n++)
11    {
12        auto v = base;
13        for (auto&amp; m : v) m *= n;
14        vRet.push_back(v);
15    }
16    return vRet;
17}
18
19template&lt;typename T&gt;
20struct sumGreaterThan
21{
22    T _limit{ 0 };
23
24    auto operator()(const std::vector&lt;T&gt;&amp; v) {return std::accumulate(v.cbegin(), v.cend(), 0) &gt; _limit;}
25};
26   
27int main()
28{
29    using namespace std;
30    vector&lt;int&gt; nums{1,2,3,4,5,6,7,8,9};
31
32    auto mults = buildMultiples(nums);
33
34    for (auto&amp; m : buildMultiples(nums)) {} //1. Compiles
35
36    sumGreaterThan sumFilter{ 10 };
37    
38    auto vecs = buildMultiples(nums);
39    for (auto&amp; m : vecs | views::filter(sumFilter)) {} //2. Compiles
40
41    for (auto&amp; m : buildMultiples(nums) | views::filter(sumFilter)) {} //3. Compilation Error!!
42
43    for (auto vecs = buildMultiples(nums); auto &amp; m : vecs | views::filter(sumFilter)) {} // 4. Compiles. Thanks @Aryter
44}
45vecs | views::filter(sumFilter)
46

whereas this is passing an rvalue vector into filter:

1'|': no operator found which takes a left-hand operand of type 'std::vector&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;,std::allocator&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;&gt;&gt;' (or there is no acceptable conversion)  
2#include &lt;vector&gt;
3#include &lt;numeric&gt;
4#include &lt;ranges&gt;
5
6template&lt;typename T&gt;
7auto buildMultiples(const std::vector&lt;T&gt;&amp; base)
8{
9    std::vector&lt;std::vector&lt;T&gt;&gt; vRet;
10    for(T n= 1; n &lt;= 5; n++)
11    {
12        auto v = base;
13        for (auto&amp; m : v) m *= n;
14        vRet.push_back(v);
15    }
16    return vRet;
17}
18
19template&lt;typename T&gt;
20struct sumGreaterThan
21{
22    T _limit{ 0 };
23
24    auto operator()(const std::vector&lt;T&gt;&amp; v) {return std::accumulate(v.cbegin(), v.cend(), 0) &gt; _limit;}
25};
26   
27int main()
28{
29    using namespace std;
30    vector&lt;int&gt; nums{1,2,3,4,5,6,7,8,9};
31
32    auto mults = buildMultiples(nums);
33
34    for (auto&amp; m : buildMultiples(nums)) {} //1. Compiles
35
36    sumGreaterThan sumFilter{ 10 };
37    
38    auto vecs = buildMultiples(nums);
39    for (auto&amp; m : vecs | views::filter(sumFilter)) {} //2. Compiles
40
41    for (auto&amp; m : buildMultiples(nums) | views::filter(sumFilter)) {} //3. Compilation Error!!
42
43    for (auto vecs = buildMultiples(nums); auto &amp; m : vecs | views::filter(sumFilter)) {} // 4. Compiles. Thanks @Aryter
44}
45vecs | views::filter(sumFilter)
46buildMultiples(nums) | views::filter(sumFilter)
47

The current rule, which compilers implement, is that range adaptor pipelines cannot take rvalue non-view ranges (like vector, string, etc.). This is because the pipeline itself is non-owning (views were non-owning), and exists as a safety mechanism to prevent dangling.

The new rule, recently adopted as a defect, would allow this could and would cause filter to own the result of buildMultiples (this is P2415), but compilers don't implement it quite yet. With this change, your other version would also have compiled.

So for now, you will have to keep writing it this way (as you are already doing):

1'|': no operator found which takes a left-hand operand of type 'std::vector&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;,std::allocator&lt;std::vector&lt;int,std::allocator&lt;int&gt;&gt;&gt;&gt;' (or there is no acceptable conversion)  
2#include &lt;vector&gt;
3#include &lt;numeric&gt;
4#include &lt;ranges&gt;
5
6template&lt;typename T&gt;
7auto buildMultiples(const std::vector&lt;T&gt;&amp; base)
8{
9    std::vector&lt;std::vector&lt;T&gt;&gt; vRet;
10    for(T n= 1; n &lt;= 5; n++)
11    {
12        auto v = base;
13        for (auto&amp; m : v) m *= n;
14        vRet.push_back(v);
15    }
16    return vRet;
17}
18
19template&lt;typename T&gt;
20struct sumGreaterThan
21{
22    T _limit{ 0 };
23
24    auto operator()(const std::vector&lt;T&gt;&amp; v) {return std::accumulate(v.cbegin(), v.cend(), 0) &gt; _limit;}
25};
26   
27int main()
28{
29    using namespace std;
30    vector&lt;int&gt; nums{1,2,3,4,5,6,7,8,9};
31
32    auto mults = buildMultiples(nums);
33
34    for (auto&amp; m : buildMultiples(nums)) {} //1. Compiles
35
36    sumGreaterThan sumFilter{ 10 };
37    
38    auto vecs = buildMultiples(nums);
39    for (auto&amp; m : vecs | views::filter(sumFilter)) {} //2. Compiles
40
41    for (auto&amp; m : buildMultiples(nums) | views::filter(sumFilter)) {} //3. Compilation Error!!
42
43    for (auto vecs = buildMultiples(nums); auto &amp; m : vecs | views::filter(sumFilter)) {} // 4. Compiles. Thanks @Aryter
44}
45vecs | views::filter(sumFilter)
46buildMultiples(nums) | views::filter(sumFilter)
47auto vecs = buildMultiples(nums);
48for (auto&amp; m : vecs | views::filter(sumFilter)) { ... }
49

Source https://stackoverflow.com/questions/70191692

QUESTION

Apply a filter on a multilevel object based on a different object

Asked 2021-Nov-25 at 21:30

I have an array with multilevel objects, such as:

1list= [ {  
2           type: { name: 'dog', size:'medium'},
3           entity: { name: 'Tobby',  age: '7'},
4         },
5         {  
6           type: { name: 'cat', size:'small'},
7           entity: { name: 'Garfield',  age: '7'},
8         }
9    ]
10

And I have a defined filter such as:

1list= [ {  
2           type: { name: 'dog', size:'medium'},
3           entity: { name: 'Tobby',  age: '7'},
4         },
5         {  
6           type: { name: 'cat', size:'small'},
7           entity: { name: 'Garfield',  age: '7'},
8         }
9    ]
10filter={
11         type: { name:'dog'}}
12

I need to define a function such that I can call

1list= [ {  
2           type: { name: 'dog', size:'medium'},
3           entity: { name: 'Tobby',  age: '7'},
4         },
5         {  
6           type: { name: 'cat', size:'small'},
7           entity: { name: 'Garfield',  age: '7'},
8         }
9    ]
10filter={
11         type: { name:'dog'}}
12let filtered = list.thisMagicFilter(filter)
13

that will filter accordingly on my list (in the given example, returning only the first element.

Logically, if the filter is {entity:{age:'7'}}, then both results should be returned.

I've broken my head trying to do this in a functional programming with a list.filter(), but it's just too complex for me: I'm struggling on the fact that it's a 2 level validation.

Can I get some hint of how to tackle this problem?

Thank you in advance!

ANSWER

Answered 2021-Nov-25 at 21:25

Try this:

1list= [ {  
2           type: { name: 'dog', size:'medium'},
3           entity: { name: 'Tobby',  age: '7'},
4         },
5         {  
6           type: { name: 'cat', size:'small'},
7           entity: { name: 'Garfield',  age: '7'},
8         }
9    ]
10filter={
11         type: { name:'dog'}}
12let filtered = list.thisMagicFilter(filter)
13const _matchesFilter = (e, conditions = []) =&gt;
14  conditions.every(([prop, condition]) =&gt; {
15    const subConditions = Object.entries(condition);
16    return subConditions.every(([ subProp, subCondition ]) =&gt;
17      e[prop]?.[subProp] === subCondition
18    );
19  });
20
21const thisMagicFilter = (list = [], filter = {}) =&gt; {
22  const conditions = Object.entries(filter);
23  return list.filter(e =&gt; _matchesFilter(e, conditions));
24}
25
26const list= [ 
27  { type: { name: 'dog', size:'medium'}, entity: { name: 'Tobby',  age: '7'} },
28  { type: { name: 'cat', size:'small'}, entity: { name: 'Garfield',  age: '7'} }
29];
30console.log( thisMagicFilter(list) );
31console.log( thisMagicFilter(list, { type: { name: 'dog'} }) );
32console.log( thisMagicFilter(list, { entity: { age: '7'} }) );
33console.log( thisMagicFilter(list, { entity: { name: 'Garfield', age: '7'} }) );
34console.log( thisMagicFilter(list, { type: { size: 'medium' }, entity: { age: '7'} }) );

Source https://stackoverflow.com/questions/70117321

QUESTION

What is the relationship between monad functions dist and join in Haskell?

Asked 2021-Nov-22 at 12:41

I was doing one of the homeworks from functional programming course and found some problems understanding monads in Haskell.

So, we were given a type:

1data Annotated e a = a :# e
2infix 0 :#
3

The task was to implement some functions with given type signatures, which I did. They pass needed tests (separately):

1data Annotated e a = a :# e
2infix 0 :#
3mapAnnotated :: (a -&gt; b) -&gt; (Annotated e a -&gt; Annotated e b)
4mapAnnotated f (x :# w) = f x :# w
5
6joinAnnotated :: Semigroup e =&gt; Annotated e (Annotated e a) -&gt; Annotated e a
7joinAnnotated ((b :# m) :# n) = b :# m &lt;&gt; n
8
9distAnnotated :: Semigroup e =&gt; (Annotated e a, Annotated e b) -&gt; Annotated e (a, b)
10distAnnotated (x :# m, y :# n) = (x, y) :# m &lt;&gt; n
11

However, we were also asked to satisfy following equation:

1data Annotated e a = a :# e
2infix 0 :#
3mapAnnotated :: (a -&gt; b) -&gt; (Annotated e a -&gt; Annotated e b)
4mapAnnotated f (x :# w) = f x :# w
5
6joinAnnotated :: Semigroup e =&gt; Annotated e (Annotated e a) -&gt; Annotated e a
7joinAnnotated ((b :# m) :# n) = b :# m &lt;&gt; n
8
9distAnnotated :: Semigroup e =&gt; (Annotated e a, Annotated e b) -&gt; Annotated e (a, b)
10distAnnotated (x :# m, y :# n) = (x, y) :# m &lt;&gt; n
11distAnnotated (p, q) = joinAnnotated (mapAnnotated (\a -&gt; mapAnnotated (\b -&gt; (a, b)) q) p)
12

I can't quite get my head around so many function applications, so for other types with similar tasks I just did what seemed "natural" and it worked, but here it doesn't and I can't see why, since I don't even see other ways to implement these functions. What am I missing?

ANSWER

Answered 2021-Nov-21 at 19:19

Let's start with the troublesome equation and systematically substitute the definitions, working it inside-out:

1data Annotated e a = a :# e
2infix 0 :#
3mapAnnotated :: (a -&gt; b) -&gt; (Annotated e a -&gt; Annotated e b)
4mapAnnotated f (x :# w) = f x :# w
5
6joinAnnotated :: Semigroup e =&gt; Annotated e (Annotated e a) -&gt; Annotated e a
7joinAnnotated ((b :# m) :# n) = b :# m &lt;&gt; n
8
9distAnnotated :: Semigroup e =&gt; (Annotated e a, Annotated e b) -&gt; Annotated e (a, b)
10distAnnotated (x :# m, y :# n) = (x, y) :# m &lt;&gt; n
11distAnnotated (p, q) = joinAnnotated (mapAnnotated (\a -&gt; mapAnnotated (\b -&gt; (a, b)) q) p)
12-- Given
13mapAnnotated f (x :# w) = f x :# w
14joinAnnotated ((b :# m) :# n) = b :# m &lt;&gt; n
15distAnnotated (x :# m, y :# n) = (x, y) :# m &lt;&gt; n
16p = x :# m
17q = y :# n
18
19-- Goal
20distAnnotated (p, q) = joinAnnotated (mapAnnotated (\a -&gt; mapAnnotated (\b -&gt; (a, b)) q) p)
21
22-- Right-hand side
23joinAnnotated (mapAnnotated (\a -&gt; mapAnnotated (\b -&gt; (a, b)) q) p)
24joinAnnotated (mapAnnotated (\a -&gt; mapAnnotated (\b -&gt; (a, b)) (y :# n)) (x :# m))
25joinAnnotated (mapAnnotated (\a -&gt; (\b -&gt; (a, b)) y :# n) (x :# m))
26joinAnnotated (mapAnnotated (\a -&gt; (a, y) :# n) (x :# m))
27joinAnnotated (mapAnnotated (\a -&gt; (a, y) :# n) (x :# m))
28joinAnnotated ((\a -&gt; (a, y) :# n) x :# m)
29joinAnnotated (((x, y) :# n) :# m)
30(x, y) :# n &lt;&gt; m
31-- Left-hand side
32distAnnotated (p, q)
33distAnnotated (x :# m, y :# n)
34(x, y) :# m &lt;&gt; n
35-- LHS /= RHS
36

The problem, therefore, is that distAnnotated combines the annotations in a different order than joinAnnotated (m <> n versus n <> m). The usual way to make them agree is changing joinAnnotated so that the outside annotation comes first:

1data Annotated e a = a :# e
2infix 0 :#
3mapAnnotated :: (a -&gt; b) -&gt; (Annotated e a -&gt; Annotated e b)
4mapAnnotated f (x :# w) = f x :# w
5
6joinAnnotated :: Semigroup e =&gt; Annotated e (Annotated e a) -&gt; Annotated e a
7joinAnnotated ((b :# m) :# n) = b :# m &lt;&gt; n
8
9distAnnotated :: Semigroup e =&gt; (Annotated e a, Annotated e b) -&gt; Annotated e (a, b)
10distAnnotated (x :# m, y :# n) = (x, y) :# m &lt;&gt; n
11distAnnotated (p, q) = joinAnnotated (mapAnnotated (\a -&gt; mapAnnotated (\b -&gt; (a, b)) q) p)
12-- Given
13mapAnnotated f (x :# w) = f x :# w
14joinAnnotated ((b :# m) :# n) = b :# m &lt;&gt; n
15distAnnotated (x :# m, y :# n) = (x, y) :# m &lt;&gt; n
16p = x :# m
17q = y :# n
18
19-- Goal
20distAnnotated (p, q) = joinAnnotated (mapAnnotated (\a -&gt; mapAnnotated (\b -&gt; (a, b)) q) p)
21
22-- Right-hand side
23joinAnnotated (mapAnnotated (\a -&gt; mapAnnotated (\b -&gt; (a, b)) q) p)
24joinAnnotated (mapAnnotated (\a -&gt; mapAnnotated (\b -&gt; (a, b)) (y :# n)) (x :# m))
25joinAnnotated (mapAnnotated (\a -&gt; (\b -&gt; (a, b)) y :# n) (x :# m))
26joinAnnotated (mapAnnotated (\a -&gt; (a, y) :# n) (x :# m))
27joinAnnotated (mapAnnotated (\a -&gt; (a, y) :# n) (x :# m))
28joinAnnotated ((\a -&gt; (a, y) :# n) x :# m)
29joinAnnotated (((x, y) :# n) :# m)
30(x, y) :# n &lt;&gt; m
31-- Left-hand side
32distAnnotated (p, q)
33distAnnotated (x :# m, y :# n)
34(x, y) :# m &lt;&gt; n
35-- LHS /= RHS
36joinAnnotated ((b :# m) :# n) = b :# n &lt;&gt; m
37

This fits both the natural sequencing of computations in the monadic bind (m >>= f = joinAnnotated (mapAnnotated f m)) and the conventional left-to-right order of applicative effects (p <*> q = ap p q = mapAnnotated (\(f, a) -> f a) (distAnnotated (p, q))).

Source https://stackoverflow.com/questions/70057113

QUESTION

How to Log in F# in a functional way using NLog

Asked 2021-Nov-21 at 15:55

I have been looking at logging options and settled on NLog and logging to a database

I am fairly new to functional programming and have come from a background in C# OOP.

How would I implement logging in a functional way in F#?
Do I

  • Create the logger at the top level and just pass it in to every function as I go
  • Access the logger through a static method as needed ( obviously there would be some overhead to instantiating a logger each time - but maybe that's not a big deal )
  • Something else?

I want to avoid using a commercial logging option just because my projects are quite small.

Thanks for your time.

ANSWER

Answered 2021-Nov-20 at 00:43

As logging is inherently impure there isn't a particularly clean way to do logging that I'm aware of. You have basically identified the two solutions in your question. Which one you use depends on what the logs are being used for.

For logging to external services I would consider creating an AppContext type which is home to app and user settings as well as providing functions or methods for logging to e.g. a database. This type should be added an extra parameter in your functions or an additional field in your types depending on what makes the most sense.

For your lowest-level functions rather than changing them all to accept an additional parameter you should consider altering the return type to include the information you want to log and leaving the act of logging to higher level parts of your program.

For logging to a console, rolling buffer, or other temporary location I think it is fine to create a module which is equivalent to a C# static class and just provide globally accessible logging functions.

Source https://stackoverflow.com/questions/70040464

QUESTION

Idiomatically moving/sorting values from one Vec into another

Asked 2021-Sep-22 at 22:48

I recently picked up rust, coming from a python background. I'm still getting the hang of functional programming so I'm looking for insight/feedback on writing idiomatic rust.

In the example below I have a list of Parent elements and Child elements and want to sort the Child elements into their respective parents based off of an id.

In python I would nest two for loops, perform a test and continue accordingly. But I'm not quite sure if there is a better/performant/idiomatic way of doing this.

I've marked the section of the code in question. Although any feedback is great!

Here's a working playgound: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=233cfa5b5798090fa969ba348a479b1c

1#[derive(Debug)]
2struct Parent {
3    id: String,
4    children: Vec&lt;Child&gt;,
5}
6
7impl Parent {
8    pub fn from_id(id: String) -&gt; Self {
9        Self {
10            id,
11            children: Vec::new(),
12        }
13    }
14}
15
16#[derive(Debug)]
17struct Child {
18    parent_id: String,
19}
20
21impl Child {
22    pub fn from_parent_id(parent_id: String) -&gt; Self {
23        Self { parent_id }
24    }
25}
26
27fn main() {
28    let mut parents: Vec&lt;Parent&gt; = vec![&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]
29        .iter()
30        .map(|s| s.to_string())
31        .map(Parent::from_id)
32        .collect();
33
34    let mut children: Vec&lt;Child&gt; = vec![&quot;a&quot;, &quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;c&quot;, &quot;c&quot;]
35        .iter()
36        .map(|s| s.to_string())
37        .map(Child::from_parent_id)
38        .collect();
39
40    // Is there a better way to do this?
41    while let Some(child) = children.pop() {
42        for parent in parents.iter_mut() {
43            if child.parent_id == parent.id {
44                parent.children.push(child);
45                break;
46            }
47        }
48    }
49
50    dbg!(parents);
51    dbg!(children);
52}
53

ANSWER

Answered 2021-Sep-22 at 06:49

Popping items off the end of the vector is mostly used when you need to retain parts or all of the vector. If you need to consume the whole vector, you can pass it to the for loop directly:

1#[derive(Debug)]
2struct Parent {
3    id: String,
4    children: Vec&lt;Child&gt;,
5}
6
7impl Parent {
8    pub fn from_id(id: String) -&gt; Self {
9        Self {
10            id,
11            children: Vec::new(),
12        }
13    }
14}
15
16#[derive(Debug)]
17struct Child {
18    parent_id: String,
19}
20
21impl Child {
22    pub fn from_parent_id(parent_id: String) -&gt; Self {
23        Self { parent_id }
24    }
25}
26
27fn main() {
28    let mut parents: Vec&lt;Parent&gt; = vec![&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]
29        .iter()
30        .map(|s| s.to_string())
31        .map(Parent::from_id)
32        .collect();
33
34    let mut children: Vec&lt;Child&gt; = vec![&quot;a&quot;, &quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;c&quot;, &quot;c&quot;]
35        .iter()
36        .map(|s| s.to_string())
37        .map(Child::from_parent_id)
38        .collect();
39
40    // Is there a better way to do this?
41    while let Some(child) = children.pop() {
42        for parent in parents.iter_mut() {
43            if child.parent_id == parent.id {
44                parent.children.push(child);
45                break;
46            }
47        }
48    }
49
50    dbg!(parents);
51    dbg!(children);
52}
53for child in children {
54    for parent in parents.iter_mut() {
55        if child.parent_id == parent.id {
56            parent.children.push(child);
57            break;
58        }
59    }
60}
61

You can use iterators to look for the parent, like this:

1#[derive(Debug)]
2struct Parent {
3    id: String,
4    children: Vec&lt;Child&gt;,
5}
6
7impl Parent {
8    pub fn from_id(id: String) -&gt; Self {
9        Self {
10            id,
11            children: Vec::new(),
12        }
13    }
14}
15
16#[derive(Debug)]
17struct Child {
18    parent_id: String,
19}
20
21impl Child {
22    pub fn from_parent_id(parent_id: String) -&gt; Self {
23        Self { parent_id }
24    }
25}
26
27fn main() {
28    let mut parents: Vec&lt;Parent&gt; = vec![&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]
29        .iter()
30        .map(|s| s.to_string())
31        .map(Parent::from_id)
32        .collect();
33
34    let mut children: Vec&lt;Child&gt; = vec![&quot;a&quot;, &quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;c&quot;, &quot;c&quot;]
35        .iter()
36        .map(|s| s.to_string())
37        .map(Child::from_parent_id)
38        .collect();
39
40    // Is there a better way to do this?
41    while let Some(child) = children.pop() {
42        for parent in parents.iter_mut() {
43            if child.parent_id == parent.id {
44                parent.children.push(child);
45                break;
46            }
47        }
48    }
49
50    dbg!(parents);
51    dbg!(children);
52}
53for child in children {
54    for parent in parents.iter_mut() {
55        if child.parent_id == parent.id {
56            parent.children.push(child);
57            break;
58        }
59    }
60}
61for child in children {
62    parents
63        .iter_mut()
64        .find(|parent| parent.id == child.parent_id)
65        .map(|parent| parent.children.push(child));
66}
67

The most important issue with performance is that this needs to perform n*m iterations in total, where n and m are number of parents and children. If those numbers can go into tens of thousands, you will end up with hundreds of millions of iterations, which will slow you down. You can create a temporary mapping of id->position for the parents vector can make the operation O(n + m):

1#[derive(Debug)]
2struct Parent {
3    id: String,
4    children: Vec&lt;Child&gt;,
5}
6
7impl Parent {
8    pub fn from_id(id: String) -&gt; Self {
9        Self {
10            id,
11            children: Vec::new(),
12        }
13    }
14}
15
16#[derive(Debug)]
17struct Child {
18    parent_id: String,
19}
20
21impl Child {
22    pub fn from_parent_id(parent_id: String) -&gt; Self {
23        Self { parent_id }
24    }
25}
26
27fn main() {
28    let mut parents: Vec&lt;Parent&gt; = vec![&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]
29        .iter()
30        .map(|s| s.to_string())
31        .map(Parent::from_id)
32        .collect();
33
34    let mut children: Vec&lt;Child&gt; = vec![&quot;a&quot;, &quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;c&quot;, &quot;c&quot;]
35        .iter()
36        .map(|s| s.to_string())
37        .map(Child::from_parent_id)
38        .collect();
39
40    // Is there a better way to do this?
41    while let Some(child) = children.pop() {
42        for parent in parents.iter_mut() {
43            if child.parent_id == parent.id {
44                parent.children.push(child);
45                break;
46            }
47        }
48    }
49
50    dbg!(parents);
51    dbg!(children);
52}
53for child in children {
54    for parent in parents.iter_mut() {
55        if child.parent_id == parent.id {
56            parent.children.push(child);
57            break;
58        }
59    }
60}
61for child in children {
62    parents
63        .iter_mut()
64        .find(|parent| parent.id == child.parent_id)
65        .map(|parent| parent.children.push(child));
66}
67let parent_pos_by_id: HashMap&lt;_, _&gt; = parents
68    .iter()
69    .enumerate()
70    .map(|(idx, parent)| (parent.id.clone(), idx))
71    .collect();
72
73for child in children {
74    if let Some(&amp;parent_pos) = parent_pos_by_id.get(&amp;child.parent_id) {
75        parents[parent_pos].children.push(child);
76    }
77}
78

Source https://stackoverflow.com/questions/69274529

Community Discussions contain sources that include Stack Exchange Network

Tutorials and Learning Resources in Functional Programming

Tutorials and Learning Resources are not available at this moment for Functional Programming

Share this Page

share link

Get latest updates on Functional Programming