Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I iterate over Dictionary values? #8

Closed
Aeres-u99 opened this issue Feb 9, 2020 · 5 comments
Closed

How do I iterate over Dictionary values? #8

Aeres-u99 opened this issue Feb 9, 2020 · 5 comments
Labels

Comments

@Aeres-u99
Copy link

Aeres-u99 commented Feb 9, 2020

So basically I have a dictionary

d = {
"1":"foo",
"2":"bar",
"3":"spam",
"4":"Eggs"
}

I would like to be able to search through foo,bar etc and return the corresponding id. Even If I could get the key and value both of selection, that'd be fine as well.
I have tried following:

iterfzf(d,multi=True) which basically allows me to select the keys as dictionaries are iterable over keys.
then
iterfzf(d.values(),multi=True) shows nothing else other than 0 0 and exits without any errors
iterfzf(d.items(),multi=True) shows some weird behaviour and error as follows:

(tgD) > cat __init__.py                                                                                                finder
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: __init__.py
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ from iterfzf import iterfzf
   2   │ 
   3   │ 
   4   │ d = {
   5   │     "1":'Message',
   6   │     "2":'Message',
   7   │     "3":'Message',
   8   │     "4":'keke',
   9   │      }
  10   │ a = iterfzf(d.items(),multi=True)
  11   │ print(a)
───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
(tgD) > python3 __init__.py                                                                                            finder
Traceback (most recent call last):
                                    File "__init__.py", line 10, in <module>
                                                                                a = iterfzf(d.items(),multi=True)
                                                                                                                   File "/home/akuma/SoopaProject/TelegramProjects/tgD/tgD/lib/python3.6/site-packages/iterfzf/__init__.py", line 81, in iterfzf
                                                                                                                      line = line.encode(encoding)
                    AttributeError: 'tuple' object has no attribute 'encode'
                                                                            Failed to read /dev/tty

It shows the error in exact disoriented manner.

I would like to know the correct way to achieve the desired result as well as once specified would go ahead and make the pr with appropriate inclusion in documentation. Thank you for this awesome module and for your generous time.
using d.iteritems gives following Error:

(tgD) > python3 __init__.py                                                                                            finder
Traceback (most recent call last):
                                    File "__init__.py", line 10, in <module>
                                                                                a = iterfzf(d.iteritems(),multi=True)
                                                                                                                     AttributeError: 'dict' object has no attribute 'iteritems'
                                                 %                                                                            (tgD) >                                                                                                           finder RC=1

EDIT: Added the iteritems error

@dahlia
Copy link
Owner

dahlia commented Feb 9, 2020

Currently iterfzf() only accepts Unicode strings (i.e., str) or byte strings (i.e., bytes), not arbitrary Python objects like tuples. That's why iterfzf(d.items()) raises an error, as dict.items() returns an iterable of pairs, not strings.

As iterfzf() takes only strings and there is no way to give each item some “hidden keys” besides displayed values (and I believe it's same to fzf), you need to give iterfzf() string representations of key–value pairs. Here's an example:

from iterfzf import iterfzf


def fzf_dict(d, multi):
    options = ('{0}\t{1}'.format(k, v) for k, v in d.items())
    for kv in iterfzf(options, multi=multi):
        yield kv[:kv.index('\t')]


def main():
    d = {
        '1': 'foo',
        '2': 'bar',
        '3': 'spam',
        '4': 'egg',
    }
    print(iterfzf(d.values()))
    keys = fzf_dict(d, multi=True)
    for key in keys:
        print(repr(key), '=>', repr(d[key]))


if __name__ == '__main__':
    main()

The above code assumes keys must have no tabs, hence '\t' as a separator.

iterfzf(d.values(),multi=True) shows nothing else other than 0 0 and exits without any errors

I believe iterfzf(d.values()) must show dictionary values, but I am not sure why you've experienced that. I guess it's because you did it in an IPython session, which directly deals with TTY?

@dahlia dahlia added the question label Feb 9, 2020
@Aeres-u99
Copy link
Author

Ahh thank you very much for explanation. Should we add this into the documentation as well? It will come in very handy. Are we planning to change it in anyways in near future?

@dahlia
Copy link
Owner

dahlia commented Feb 9, 2020

I believe the limitation (that it takes only strings) should be fixed in the upstream fzf project. In the docs I already wrote it only accepts Unicode strings or byte strings. Or do you mean other part of the docs?

@Aeres-u99
Copy link
Author

I mean the workaround for these, like the one you just suggested to me. imho this is fantastic I will definitely want to see more of the development :D

dahlia added a commit that referenced this issue Feb 9, 2020
@dahlia
Copy link
Owner

dahlia commented Feb 9, 2020

Okay, I added the example code into the repository's examples/ directory:

iterfzf/examples/kv.py

Lines 1 to 34 in 2d13fdf

"""Currently ``fzf`` and ``iterfzf()`` takes only some kind of strings,
so you can't pass arbitrary Python objects into that. Also there is no way
to give each item some "hidden keys" besides displayed values.
Therefore, if you want to show items in a dictionary, and make users to choose
some items, then get chosen item keys, you need to give ``iterfzf()`` string
representations of key-value pairs. Here's an example:
"""
from iterfzf import iterfzf
def fzf_dict(d, multi):
r"""This assumes keys must have no tabs, hence ``'\t'`` as a separator."""
options = ('{0}\t{1}'.format(k, v) for k, v in d.items())
for kv in iterfzf(options, multi=multi):
yield kv[:kv.index('\t')]
def main():
d = {
'1': 'foo',
'2': 'bar',
'3': 'spam',
'4': 'egg',
}
print(iterfzf(d.values()))
keys = fzf_dict(d, multi=True)
for key in keys:
print(repr(key), '=>', repr(d[key]))
if __name__ == '__main__':
main()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants