0

Update: Sorry for not using carefully break and continue, whole logic changed just by replacing continue by break, sorry for posting without fundamentals cleared.

I have read this solution but didn't understand.

context: I am working on Odoo framework, and making api call, getting response in list of dictionaries.

response list is very large and I wanted only id, name from that, to add it in database, by making new list of dictionaries.

but when I call update function, it adds values again, so I want to check if that id uniquely exist then skip append, else add that value to list.

api response is like this:

rooms_list = [
    {
        "id": 1,
        "name": "A",
        "rates": "dictA"
    },
    {
        "id": 2,
        "name": "B",
        "rates": "dictB"
    },
    {
        "id": 3,
        "name": "C",
        "rates": "dictC"
    },
]

and my current list is having few values initially as:

new_list = [
    {
        "id": 1,
        "name": "A"
    },
    {
        "id":2,
        "name":"B"
    }
]

now, it should add only last dictionary to list but it adds redundant values, where am I making mistake?

my whole code is as follows:

print("new_list initially is => ", new_list)
one_record = {}

for i in rooms_list:
    for j in new_list:
        one_record = {}

        print("j is ", j)
        if j["id"] == i["id"]:
            print("escape this record because it exist already in our new_list")
            continue
        else:
            print("else add it in our new_list")
            one_record["id"] = i["id"],
            one_record["name"] = i["name"],

    if one_record != {}:
        print("one_record is not empty for j =>", j)
        new_list.append(one_record)

print("rooms_list is ", rooms_list)
print("new_list is  ", new_list)

and output is as:

('rooms_list is ', [{'rates': 'dictA', 'id': 1, 'name': 'A'}, {'rates': 'dictB', 'id': 2, 'name': 'B'}, {'rates': 'dictC', 'id': 3, 'name': 'C'}])
('new_list is  ', [{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'B'}, {'id': (1,), 'name': ('A',)}, {'id': (2,), 'name': ('B',)}, {'id': (3,), 'name': ('C',)}])

screenshot

how can I add new dictionaries without redundant id ?

Dan
  • 45,079
  • 17
  • 88
  • 157
GD- Ganesh Deshmukh
  • 1,456
  • 3
  • 24
  • 36
  • 2
    Instead of putting SOLVED in your question title, you should just accept one of the answers here – Dan Oct 03 '19 at 14:09

4 Answers4

2

You could use a simple loop like this:

for i in rooms_list:
    if i['id'] not in [item['id'] for item in new_list]:
        new_list.append(i)
print(new_list)

which gives:

[{'id': 1, 'name': 'A'},
 {'id': 2, 'name': 'B'},
 {'id': 3, 'name': 'C', 'rates': 'dictC'}]
ExplodingGayFish
  • 2,807
  • 1
  • 5
  • 14
  • 3
    It's very inefficient to recreate the list of ids at each loop iteration. Why not just do `[item['id'] for item in new_list]` before the loop and then append to that as you need as well. Otherwise you're going to get O(n^2) runtime when you could have O(n). – Dan Oct 03 '19 at 09:34
  • 1
    Also for using `in` I would highly recommend a set rather than a list: https://stackoverflow.com/a/17945009/1011724 – Dan Oct 03 '19 at 09:37
2

Since you are only interested in IDs and names, you can switch from a list of dict to a single dict:

new_dict = {entry['id']: entry['name'] for entry in new_list}

Then it's a matter of properly using dict.setdefault which does exactly what you want: insert a value unless the key already exists:

for entry in rooms_list:
    new_dict.setdefault(entry['id'], entry['name'])

If you still need a list afterwards, you can easily convert new_dict to a list again:

new_list = [{'id': id, 'name': name} for id, name in new_dict.items()]

Note that since CPython 3.6, this approach will also keep the order of items.

301_Moved_Permanently
  • 4,007
  • 14
  • 28
1

I would maintain a set of ids:

given

new_list = [
    {
        "id": 1,
        "name": "A"
    },
    {
        "id":2,
        "name":"B"
    }
]

create a set of ids

ids = set(entry["id"] for entry in new_list)

then

for entry in rooms_list:
    id = entry["id"]
    name = entry["name"
    if id not in ids:
        new_list += {"id": id, "name": name}
        ids.add(id)

A better option would be to create a dictionary like this instead of your new_list since it contains all the same information in much less space and will enforce unique ids by itself:

better_new_list = {
    1: "A",
    2: "B",
}

now adding to it would be this:

for entry in rooms_list:
    id = entry["id"]
    name = entry["name"]
    if id not in better_new_list:
        better_new_list[id] = name
Dan
  • 45,079
  • 17
  • 88
  • 157
  • thanks @Dan, for telling to use "set", so useful, but I used most of times, list only. will do that. – GD- Ganesh Deshmukh Oct 03 '19 at 09:30
  • @ganeshdeshmukh I really recommend the second solution I posted here though. It's a lot more efficient and uses the data structures in a more familiar way i.e. a dictionary that uses id as it's key and name as its value. – Dan Oct 03 '19 at 09:35
-1

when id was matching I was doing continue, but it was looping for next values, when I put break, then it worked as expected.

    if j["id"] == i["id"]: 
        break

new code is

for i in rooms_list:
    for j in new_list:
        one_record = {}

        print("j is ", j)
        if j["id"] == i["id"]:
            print("escape this record because it exist already in our new_list")
            continue
        else:
GD- Ganesh Deshmukh
  • 1,456
  • 3
  • 24
  • 36
  • This is not a good solution. Try https://stackoverflow.com/a/58216324/1011724 instead, it's far more efficient. – Dan Oct 03 '19 at 14:11