Hi Monks,

Today I decided to practice some Perl by porting a Python script. What took me the most to wrap my head around was working with JSON data using JSON::XS::decode_json. In my example below, this returns an array of hashes, i.e.: [{}, {}, {}]. Therefore, I would've thought that the return value could be inferred as a list, and declared using:

@decoded = decode_json($result);

But this didn't work as expected, and this threw me off when trying to do something simple like looping on the resulting value. I found a few similar questions online and managed to finish the script, but I was wondering if there's a better way of doing this. In particular, the syntax for my $workspace (@$decoded) seems really weird to me. Do you have any thoughts on this?

For context, I'm using the i3 window manager and I often want to move windows over to the next empty workspace. This problems translates to finding the next non-consecutive number in a sequence of numbers. For example, given the workspaces 1, 2, 3, 5 and 6, while currently focusing workspace 1, this returns workspace #4. If I'm focused on workspace #5, however, it would create a new workspace at #7.

#!/bin/perl use v5.10; use strict; use warnings; use JSON::XS qw/decode_json/; use feature qw/say/; sub main { my $result = qx{ i3-msg -t get_workspaces }; # returns [{},{},{}] my $decoded = decode_json($result); my $current = 0; for my $workspace (@$decoded) { my $num = $workspace->{'num'}; if ($workspace->{'focused'}) { $current = $num; next; } # Ignore workspaces below the currently focused one. if ($current == 0) { next; } # Found the gap! if ($current + 1 != $num) { last; } # Keep increasing the soon-to-be current workspace. $current = $num; } say $current + 1; } main();

And the Python version, in case you want to give some advice on this too! :P

#!/bin/python3 import json import subprocess def main(): result = subprocess.run( ['i3-msg', '-t', 'get_workspaces'], capture_output=True, check=True ) i3_workspaces = json.loads(result.stdout) current_workspace = next((x['num'] for x in i3_workspaces if x['fo +cused'])) last_workspace = i3_workspaces[-1]['num'] remaining_workspaces = (x['num'] for x in i3_workspaces if x['num' +] >= current_workspace) for i in range(current_workspace, last_workspace): if i != next(remaining_workspaces): print(i) return print(last_workspace + 1) if __name__ == '__main__': main()

And for some fun, I decided to compare the performance of each. I know it's a really simple script and the test is basically meaningless, but I was curious, and actually the results are surprising to me:

time $(for i in {1..100}; do ./move_to_next.pl> /dev/null; done;) Perl: real 0m1.113s user 0m0.843s sys 0m0.266s Python: real 0m1.852s user 0m1.516s sys 0m0.323s

But then I changed the code to run the loop inside the program itself, basically calling `main` 100 times, and running the test again like so:

time ./move_to_next.pl > /dev/null Perl: real 0m0.231s user 0m0.116s sys 0m0.116s Python: real 0m0.099s user 0m0.078s sys 0m0.018s

So, it seems that spawning the Python interpreter itself is quite costly, but it runs faster on the long run? I also saw a video about how the JSON module in Perl is quite slow, could that be it?

Anyway, thank you in advance!


In reply to Adjusting variable context when workign with JSON data? by unmatched

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.