{"id":1920,"date":"2025-03-12T13:26:40","date_gmt":"2025-03-12T12:26:40","guid":{"rendered":"https:\/\/www.loicmathieu.fr\/wordpress\/?p=1920"},"modified":"2025-03-12T13:26:40","modified_gmt":"2025-03-12T12:26:40","slug":"benchmark-concatener-des-listes","status":"publish","type":"post","link":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/benchmark-concatener-des-listes\/","title":{"rendered":"Benchmark: concatenate lists"},"content":{"rendered":"<p>Recently, I came across this piece of code that concatenates two lists using Guava&#8217;s <code>Lists<\/code> utility class and the Stream API:<\/p>\n<pre>\nLists.newArrayList(collectionOriginal,collectionValue)\n        .stream()\n        .flatMap(Collection::stream)\n        .toList();\n<\/pre>\n<p>As this piece of code is in the hot path of the application and therefore called very frequently, I wondered if this was the best way to concatenate two lists.<\/p>\n<p>Two lists can be concatenated in many different ways:<\/p>\n<ul><li>With the above code<\/li>\n\n<li>With <code>Stream.concat()<\/code><\/li>\n\n<li>With <code>Stream.of()<\/code><\/li>\n\n<li>With <code>ListUtils<\/code> from Apache Commons Collection<\/li>\n\n<li>With <code>ArrayList.addAll()<\/code><\/li>\n<\/ul>\n<p>There are certainly other ways, but I wanted to compare these five!<\/p>\n<p>To compare these five solutions, there&#8217;s nothing better than JMH &#8211; <a href=\"https:\/\/github.com\/openjdk\/jmh\" target=\"_blank\" rel=\"noopener noreferrer\">The Java Microbenchmark Harness<\/a>. This tool enables us to write relevant microbenchmarks, taking into account the internal characteristics of the JVM. It also offers integrated tools for analyzing the performance of our tests (profiling, disassembling, etc.). If you&#8217;re not familiar with JMH, please refer to this article: <a href=\"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/introduction-a-jmh-java-microbenchmark-harness\/\" target=\"_blank\" rel=\"noopener noreferrer\">INTRODUCTION TO JMH &#8211; JAVA MICROBENCHMARK HARNESS<\/a>.<\/p>\n<h2>The benchmark<\/h2>\n<p>To be able to compare different list sizes, I use <a>@Param<\/code>code&gt;@Param&lt;\/code<\/a> to parameterize the size of the lists to be concatenated. Here&#8217;s the setup I used:<\/p>\n<pre>\n@Param({\"10\", \"1000\", \"10000\"})\nint size;\n\nList list1;\nList list2;\n\n@Setup\npublic void setup() {\n    list1 = new ArrayList(size);\n    list2 = new ArrayList(size);\n    for (int i = 0; i <\/pre>\n<p>Voici ensuite l&#8217;impl\u00e9mentation des cinq benchmarks<\/p>\n<pre>\n@Benchmark\npublic List concatWithStreamConcat() {\n    return Stream.concat(list1.stream(), list2.stream())\n            .toList();\n}\n\n@Benchmark\npublic List concatWithStreamOf() {\n    return Stream.of(list1, list2)\n            .flatMap(List::stream)\n            .toList();\n}\n\n@Benchmark\npublic List concatWithGuava() {\n    return Lists.newArrayList(list1, list2)\n            .stream()\n            .flatMap(Collection::stream)\n            .toList();\n}\n\n@Benchmark\npublic List concatWithCommonsCollection() {\n    return ListUtils.union(list1, list2);\n}\n\n@Benchmark\npublic List concatWithNewArrayList() {\n    List newList = new ArrayList(list1.size() + list2.size());\n    newList.addAll(list1);\n    newList.addAll(list2);\n    return newList;\n}\n<\/pre>\n<h2>The results<\/h2>\n<p>All tests were run on my laptop: Intel(R) Core(TM) i7-1260P 8 coeurs (16 avec hyperthreading) \u2013 Ubuntu 24.10.<\/p>\n<p>The Java version used is openjdk version &#8220;21.0.5&#8221; 2024-10-15 LTS.<\/p>\n<pre>\n Benchmark                               (size)  Mode  Cnt       Score        Error  Units\n ConcatList.concatWithCommonsCollection      10  avgt    5      57,706 \u00b1     27,376  ns\/op\n ConcatList.concatWithCommonsCollection    1000  avgt    5    1631,110 \u00b1    472,323  ns\/op\n ConcatList.concatWithCommonsCollection   10000  avgt    5   15434,192 \u00b1   2164,191  ns\/op\n ConcatList.concatWithGuava                  10  avgt    5     225,249 \u00b1     83,069  ns\/op\n ConcatList.concatWithGuava                1000  avgt    5    7967,360 \u00b1   8693,234  ns\/op\n ConcatList.concatWithGuava               10000  avgt    5  108601,706 \u00b1 104439,847  ns\/op\n ConcatList.concatWithNewArrayList           10  avgt    5      54,327 \u00b1     10,894  ns\/op\n ConcatList.concatWithNewArrayList         1000  avgt    5    1515,667 \u00b1    595,135  ns\/op\n ConcatList.concatWithNewArrayList        10000  avgt    5   14827,026 \u00b1   1253,715  ns\/op\n ConcatList.concatWithStreamConcat           10  avgt    5     111,837 \u00b1     26,451  ns\/op\n ConcatList.concatWithStreamConcat         1000  avgt    5    7104,415 \u00b1   4030,866  ns\/op\n ConcatList.concatWithStreamConcat        10000  avgt    5   57587,144 \u00b1  13994,551  ns\/op\n ConcatList.concatWithStreamOf               10  avgt    5     157,634 \u00b1     55,757  ns\/op\n ConcatList.concatWithStreamOf             1000  avgt    5    5915,797 \u00b1   1692,437  ns\/op\n ConcatList.concatWithStreamOf            10000  avgt    5   58156,102 \u00b1   1655,090  ns\/op\n<\/pre>\n<p>What&#8217;s immediately obvious is that the version used today is the worst :(.\nIf we leave it aside, we can see that <strong>concatWithStreamOf<\/strong> and <strong>concatWithStreamConcat<\/strong> perform almost identically, as do <strong>concatWithNewArrayList<\/strong> and <strong>concatWithCommonsCollection<\/strong>. A look at the code of <code>ListUtils.union(list1, list2)<\/code> shows that it does exactly what <strong>concatWithNewArrayList<\/strong> does.<\/p>\n<h2>Further analysis<\/h2>\n<p>To take the analysis a step further, let&#8217;s re-run the benchmark with JMH&#8217;s built-in GC profiler via the command-line option <code>-prof gc<\/code>, which is often a good start ;). I&#8217;m particularly interested in the memory allocation rate.<\/p>\n<pre>\nConcatList.concatWithCommonsCollection:\u00b7gc.alloc.rate.norm                   10  avgt    5     232,012 \u00b1     0,002    B\/op\nConcatList.concatWithCommonsCollection:\u00b7gc.alloc.rate.norm                 1000  avgt    5   16072,479 \u00b1     0,036    B\/op\nConcatList.concatWithCommonsCollection:\u00b7gc.alloc.rate.norm                10000  avgt    5  160077,107 \u00b1     0,434    B\/op\nConcatList.concatWithGuava:\u00b7gc.alloc.rate.norm                               10  avgt    5     888,058 \u00b1     0,009    B\/op\nConcatList.concatWithGuava:\u00b7gc.alloc.rate.norm                             1000  avgt    5   16969,104 \u00b1     0,221    B\/op\nConcatList.concatWithGuava:\u00b7gc.alloc.rate.norm                            10000  avgt    5  212148,835 \u00b1     2,822    B\/op\nConcatList.concatWithNewArrayList:\u00b7gc.alloc.rate.norm                        10  avgt    5     232,011 \u00b1     0,003    B\/op\nConcatList.concatWithNewArrayList:\u00b7gc.alloc.rate.norm                      1000  avgt    5   16072,511 \u00b1     0,040    B\/op\nConcatList.concatWithNewArrayList:\u00b7gc.alloc.rate.norm                     10000  avgt    5  160076,834 \u00b1     0,366    B\/op\nConcatList.concatWithStreamConcat:\u00b7gc.alloc.rate.norm                        10  avgt    5     424,023 \u00b1     0,006    B\/op\nConcatList.concatWithStreamConcat:\u00b7gc.alloc.rate.norm                      1000  avgt    5    8344,716 \u00b1     0,173    B\/op\nConcatList.concatWithStreamConcat:\u00b7gc.alloc.rate.norm                     10000  avgt    5   80350,980 \u00b1     1,306    B\/op\nConcatList.concatWithStreamOf:\u00b7gc.alloc.rate.norm                            10  avgt    5     824,037 \u00b1     0,007    B\/op\nConcatList.concatWithStreamOf:\u00b7gc.alloc.rate.norm                          1000  avgt    5   16905,076 \u00b1     0,208    B\/op\nConcatList.concatWithStreamOf:\u00b7gc.alloc.rate.norm                         10000  avgt    5  212083,533 \u00b1     2,497    B\/op\n<\/pre>\n<p>Here, we&#8217;re interested in the value of <code>gc.alloc.rate.norm<\/code>, which is the normalized memory allocation rate per operation, and we can see a big difference right away.<\/p>\n<p>If we take <b>ConcatList.concatWithNewArrayList<\/b> as our baseline:<\/p>\n<ul><li><strong>concatWithCommonsCollection<\/strong>: same allocation.<\/li>\n\n<li><strong>concatWithGuava<\/strong>: 4x more allocation.<\/li>\n\n<li><strong>concatWithStreamConcat<\/strong>: 2x more d&#8217;allocation.<\/li>\n\n<li><strong>concatWithStreamOf<\/strong>: 4x more allocation.<\/li>\n<\/ul>\n<p>This explains some of the differences in performance, but not all.<\/p>\n<p>Let&#8217;s run the test again with the <strong>stack<\/strong> profiler, a simple, naive profiler, integrated into JMH.<\/p>\n<pre>\n# Benchmark: fr.loicmathieu.jmh.ConcatList.concatWithCommonsCollection\n# Parameters: (size = 10)\n\n....[Thread state: RUNNABLE]........................................................................\n 33,3%  50,0% $lt;stack is empty, everything is filtered?&gt;\n 31,6%  47,4% fr.loicmathieu.jmh.ConcatList.concatWithCommonsCollection\n  1,5%   2,3% fr.loicmathieu.jmh.jmh_generated.ConcatList_concatWithCommonsCollection_jmhTest.concatWithCommonsCollection_avgt_jmhStub\n  0,1%   0,1% java.util.ArrayList.\n  0,1%   0,1% java.util.Arrays.copyOf\n  0,0%   0,0% org.apache.commons.collections4.ListUtils.union\n  0,0%   0,0% java.lang.invoke.MethodHandle.maybeCustomize\n\n# Benchmark: fr.loicmathieu.jmh.ConcatList.concatWithGuava\n# Parameters: (size = 10)\n\n....[Thread state: RUNNABLE]........................................................................\n 33,3%  50,0% $lt;stack is empty, everything is filtered?&gt;\n 19,2%  28,8% java.util.stream.SpinedBuffer.ensureCapacity\n  5,3%   8,0% java.util.stream.AbstractPipeline.wrapSink\n  3,4%   5,1% java.util.stream.ReferencePipeline.toArray\n  3,2%   4,8% java.util.stream.SpinedBuffer.copyInto\n  2,1%   3,1% fr.loicmathieu.jmh.jmh_generated.ConcatList_concatWithGuava_jmhTest.concatWithGuava_avgt_jmhStub\n  0,1%   0,1% java.util.stream.StreamSupport.stream\n  0,0%   0,0% java.util.stream.ReferencePipeline.lambda$toArray$0\n  0,0%   0,0% java.util.ArrayList.spliterator\n  0,0%   0,0% java.util.stream.SpinedBuffer.inflateSpine\n\n# Benchmark: fr.loicmathieu.jmh.ConcatList.concatWithNewArrayList\n# Parameters: (size = 10)\n\n....[Thread state: RUNNABLE]........................................................................\n 33,3%  50,0% $lt;stack is empty, everything is filtered?&gt;\n 24,4%  36,6% java.util.ArrayList.addAll\n  8,7%  13,1% fr.loicmathieu.jmh.jmh_generated.ConcatList_concatWithNewArrayList_jmhTest.concatWithNewArrayList_avgt_jmhStub\n  0,1%   0,2% java.util.Arrays.copyOf\n  0,0%   0,1% java.util.ArrayList.\n  0,0%   0,0% fr.loicmathieu.jmh.ConcatList.concatWithNewArrayList\n\n# Benchmark: fr.loicmathieu.jmh.ConcatList.concatWithStreamConcat\n# Parameters: (size = 10)\n\n....[Thread state: RUNNABLE]........................................................................\n 33,3%  50,0% $lt;stack is empty, everything is filtered?&gt;\n 22,5%  33,8% java.util.ArrayList$ArrayListSpliterator.forEachRemaining\n  5,8%   8,7% fr.loicmathieu.jmh.ConcatList.concatWithStreamConcat\n  3,7%   5,6% java.util.stream.ReferencePipeline.toArray\n  1,1%   1,7% fr.loicmathieu.jmh.jmh_generated.ConcatList_concatWithStreamConcat_jmhTest.concatWithStreamConcat_avgt_jmhStub\n  0,0%   0,1% java.util.ImmutableCollections.listFromTrustedArrayNullsAllowed\n  0,0%   0,1% java.util.stream.ReferencePipeline.lambda$toArray$0\n  0,0%   0,1% java.util.stream.StreamSupport.stream\n  0,0%   0,0% java.util.ArrayList.spliterator\n\n# Benchmark: fr.loicmathieu.jmh.ConcatList.concatWithStreamOf\n# Parameters: (size = 10)\n\n....[Thread state: RUNNABLE]........................................................................\n 33,3%  50,0% $lt;stack is empty, everything is filtered?&gt;\n 16,9%  25,4% java.util.ArrayList$ArrayListSpliterator.forEachRemaining\n  4,5%   6,8% java.util.stream.SpinedBuffer.copyInto\n  4,5%   6,7% java.util.stream.AbstractPipeline.wrapSink\n  3,4%   5,2% java.util.stream.SpinedBuffer.ensureCapacity\n  3,4%   5,0% fr.loicmathieu.jmh.jmh_generated.ConcatList_concatWithStreamOf_jmhTest.concatWithStreamOf_avgt_jmhStub\n  0,3%   0,5% java.util.stream.ReferencePipeline.toArray\n  0,1%   0,2% java.util.stream.ReferencePipeline$Head.forEach\n  0,0%   0,0% java.util.ArrayList.spliterator\n  0,0%   0,0% java.util.stream.SpinedBuffer.inflateSpine\n<\/pre>\n<p><strong>concatWithCommonsCollection<\/strong> and <strong>concatWithNewArrayList<\/strong> both use <code>java.util.Arrays.copyOf<\/code>, this method is annotated with <a>@IntrinsicCandidate<\/code>code&gt;@IntrinsicCandidate&lt;\/code<\/a> which means that there is an <em>intrinsic<\/em> that allows it to be optimized directly within the JVM. To my knowledge, even if the annotation contains <strong>Candidate<\/strong> in the name, within Oracle&#8217;s OpenJDK JVM there is always at least one intrinsic for one of the supported architectures (which may not be the case for other JVM vendors). This intrinsic enables memory-efficient copying of arrays of list elements without the need to traverse the list and copy elements one by one.<\/p>\n<p><strong>concatWithStreamConcat<\/strong> and <strong>concatWithStreamOf<\/strong> both run throught all list elements via <code>java.util.ArrayList$ArrayListSpliterator.forEachRemaining<\/code>, which is less efficient.<\/p>\n<p><strong>concatWithGuava<\/strong> will also run through all the elements in the list, but in addition will create a list with the first two lists, doubling the number of times the elements are copied!<\/p>\n<h2>Conclusion<\/h2>\n<p>The simplest code is often the most efficient, even if it&#8217;s not necessarily the most elegant.<\/p>\n<p>The JVM contains a number of intrinsics that enable array copy operations in memory, which are essential when working with large data lists or performing frequent copy operations on them.<\/p>\n<p>Of course, this optimization only makes sense if the code called is in the application&#8217;s hot path. Here, concatenation is potentially performed thousands of times per second in <a href=\"https:\/\/www.kestra.io\" rel=\"noopener\" target=\"_blank\">Kestra<\/a>, so it&#8217;s important that it performs in the most efficient way.<\/p>\n<p>As a reminder, this article contains numbers, which are just that: numbers. They can be very different from one context to another. It&#8217;s always best to make your own benchmarks, in your own context, and then validate them in a real environment to deduce their relevance.<\/p>\n<p>For the curious, here&#8217;s the PR in the repo <a href=\"https:\/\/www.kestra.io\" rel=\"noopener\" target=\"_blank\">Kestra<\/a>: <a href=\"https:\/\/github.com\/kestra-io\/kestra\/pull\/7160\" rel=\"noopener\" target=\"_blank\"><a href=\"https:\/\/github.com\/kestra-io\/kestra\/pull\/7160\">https:\/\/github.com\/kestra-io\/kestra\/pull\/7160<\/a><\/a> and here is the complete benchmark: <a href=\"https:\/\/github.com\/loicmathieu\/jmh-benchmarks\/blob\/master\/src\/main\/java\/fr\/loicmathieu\/jmh\/ConcatList.java\" title=\"ConcatList.java\" rel=\"noopener\" target=\"_blank\">ConcatList.java<\/a>.\n<\/p>","protected":false},"excerpt":{"rendered":"<p>Recently, I came across this piece of code that concatenates two lists using Guava&#8217;s Lists utility class and the Stream API: Lists.newArrayList(collectionOriginal,collectionValue) .stream() .flatMap(Collection::stream) .toList(); As this piece of code is in the hot path of the application and therefore called very frequently, I wondered if this was the best way to concatenate two lists. Two lists can be concatenated in many different ways: With the above code With Stream.concat() With Stream.of() With ListUtils from Apache Commons Collection With ArrayList.addAll()&#8230;<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/benchmark-concatener-des-listes\/\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[9],"tags":[178,11,188,189,159],"class_list":["post-1920","post","type-post","status-publish","format-standard","hentry","category-informatique","tag-benchmark","tag-java","tag-jmh","tag-micro-benchmark","tag-performance"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":1030,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/for-vs-stream\/","url_meta":{"origin":1920,"position":0},"title":"(Fran\u00e7ais) For vs Stream","author":"admin","date":"Tuesday April 21st, 2020","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":739,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/les-optimisations-de-performances-de-java-9\/","url_meta":{"origin":1920,"position":1},"title":"Java 9 performance optimizations","author":"admin","date":"Friday January 26th, 2018","format":false,"excerpt":"In a previous article on Java 9, I listed all the main new features for the developers : http:\/\/www.loicmathieu.fr\/wordpress\/en\/informatique\/les-nouveautes-de-java-9-pour-les-developeurs. Here, I will list all the main performance optimizations of Java 9. I will again go through the main JEP : JEP 143: Improve Contended Locking Optimization of Java monitors (lock\u2026","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1330,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/devoxx-france-2021-ledition-9-3-4\/","url_meta":{"origin":1920,"position":2},"title":"(Fran\u00e7ais) Devoxx France 2021 &#8211; l&#8217;\u00e9dition 9 3\/4","author":"admin","date":"Friday October  1st, 2021","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1041,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/introduction-a-jmh-java-microbenchmark-harness\/","url_meta":{"origin":1920,"position":3},"title":"(Fran\u00e7ais) Introduction \u00e0 JMH &#8211; Java Microbenchmark Harness","author":"admin","date":"Wednesday April 29th, 2020","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1180,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/benchmark-conversion-de-long-en-byte\/","url_meta":{"origin":1920,"position":4},"title":"Benchmark : conversion from long to byte[]","author":"admin","date":"Tuesday December  8th, 2020","format":false,"excerpt":"I've been using Kafka a lot lately, and in Kafka a lot of things are byte arrays, even headers! As I have many components that exchange messages, I added headers to help with message tracking, including a timestamp header which has the value System.currentTimeMillis(). So I had to transform a\u2026","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":966,"url":"https:\/\/www.loicmathieu.fr\/wordpress\/informatique\/1-an-chez-zenika\/","url_meta":{"origin":1920,"position":5},"title":"(Fran\u00e7ais) 1 an chez Zenika","author":"admin","date":"Tuesday September  3rd, 2019","format":false,"excerpt":"Sorry, this entry is only available in Fran\u00e7ais.","rel":"","context":"In &quot;informatique&quot;","block_context":{"text":"informatique","link":"https:\/\/www.loicmathieu.fr\/wordpress\/category\/informatique\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts\/1920","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/comments?post=1920"}],"version-history":[{"count":10,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts\/1920\/revisions"}],"predecessor-version":[{"id":1932,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/posts\/1920\/revisions\/1932"}],"wp:attachment":[{"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/media?parent=1920"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/categories?post=1920"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.loicmathieu.fr\/wordpress\/wp-json\/wp\/v2\/tags?post=1920"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}