Topics

Arranging elements of an array

Andy B.
 

Hi,

I am trying to arrange elements in an array. This array has font and formatting information such as font, font size, and colors. A user request wanted the foreground and background colors one after the other. Unfortunately, the colors are not one after another. Does anyone have any ideas on how to rearrange elements of an array like this? Here is the code I do have at the moment.

@script(description = u"Reports formatting information for an object.")
def script_GetFontInfo(self, gesture):
focus = api.getFocusObject()
formatting = []
if shared.isWebElement(focus):
tree = focus.treeInterceptor
info = tree.makeTextInfo(textInfos.POSITION_ALL)
info.expand(textInfos.UNIT_CHARACTER)
fields = info.getTextWithFields()
for field in fields:
if isinstance (field, textInfos.FieldCommand) and isinstance (field.field, textInfos.FormatField):
for key in field.field:
formatting += [u"{}: {}".format(key, field.field[key])]
message = u"\n".join(formatting)
if getLastScriptRepeatCount() == 0:
ui.message(message)
elif getLastScriptRepeatCount() >= 1:
shared.copyToClipboard(message)
else:
message = u"Only available in web content."
ui.message(message)

 

Hi,

One way (although a bit expensive to calculate) is rearrange the array via key string look up as follows:

  1. Prepare a variable to store the index of the foreground color entry.
  2. In the inner for loop, store the index of the foreground color key right after concatenation (by the way, += is not really a good readable way to append to a list).
  3. When background color key shows up, instead of appending to the formatting list, insert background color information behind the foreground color index via list.insert method (insert it right after foreground color index (so index+1)).
  4. Proceed with iteration (just say “continue”).

 

As for append comment, what you are really doing is creating a list of lists – a simple way to just create a list of strings is just appending a string (list.append(str)). A bit more complex way (and a bit faster) is using list comprehension with conditions like so:

someList = [entry in list if condition]

 

Then build a list of format field keys and rearrange the array directly by using list.index and list.insert. Then all that’s left is build formatting list on the fly like so:

Message = “\n”.join([“{}: {}”.format(key, field.field[key]) for key in someList])

 

A simpler approach is just append each field key and entry and join these strings into a list and print them.

Cheers,

Joseph

 

From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Andy B.
Sent: Wednesday, November 27, 2019 7:20 AM
To: nvda-addons@nvda-addons.groups.io
Subject: [nvda-addons] Arranging elements of an array

 

Hi,

 

I am trying to arrange elements in an array. This array has font and formatting information such as font, font size, and colors. A user request wanted the foreground and background colors one after the other. Unfortunately, the colors are not one after another. Does anyone have any ideas on how to rearrange elements of an array like this? Here is the code I do have at the moment.

 

@script(description = u"Reports formatting information for an object.")
def script_GetFontInfo(self, gesture):
focus = api.getFocusObject()
formatting = []
if shared.isWebElement(focus):
tree = focus.treeInterceptor
info = tree.makeTextInfo(textInfos.POSITION_ALL)
info.expand(textInfos.UNIT_CHARACTER)
fields = info.getTextWithFields()
for field in fields:
if isinstance (field, textInfos.FieldCommand) and isinstance (field.field, textInfos.FormatField):
for key in field.field:
formatting += [u"{}: {}".format(key, field.field[key])]
message = u"\n".join(formatting)
if getLastScriptRepeatCount() == 0:
ui.message(message)
elif getLastScriptRepeatCount() >= 1:
shared.copyToClipboard(message)
else:
message = u"Only available in web content."
ui.message(message)

derek riemer
 

It's best to think of the order you iterate through the field as random. This is because the format fields are stored in a dictionary (a hash table), and the key is hashed down to a value. The order of keys is listed in hash order. This order could change with python versions, and thus you aren't guaranteed to have the same order of color info in the future. I would create a template string with the info you want and grab that info from the field item by item. Alternatively, you could sort the keys of the field (about Theta(n log(n)) or better with pythons sorting. This means the algorithm would take on average n*log2(n) time to complete, where n is the number of items in the field. Then, loop through your field, grab the value, and store it in a string with the key. For the number of items we have in our field, this wouldn't be too bad, and the order is guaranteed. If you want a specific order, you could pass a key function into the algorithm, adding weight to the items you want to sink to the bottom.

On Wed, Nov 27, 2019 at 8:55 AM Joseph Lee <joseph.lee22590@...> wrote:

Hi,

One way (although a bit expensive to calculate) is rearrange the array via key string look up as follows:

  1. Prepare a variable to store the index of the foreground color entry.
  2. In the inner for loop, store the index of the foreground color key right after concatenation (by the way, += is not really a good readable way to append to a list).
  3. When background color key shows up, instead of appending to the formatting list, insert background color information behind the foreground color index via list.insert method (insert it right after foreground color index (so index+1)).
  4. Proceed with iteration (just say “continue”).

 

As for append comment, what you are really doing is creating a list of lists – a simple way to just create a list of strings is just appending a string (list.append(str)). A bit more complex way (and a bit faster) is using list comprehension with conditions like so:

someList = [entry in list if condition]

 

Then build a list of format field keys and rearrange the array directly by using list.index and list.insert. Then all that’s left is build formatting list on the fly like so:

Message = “\n”.join([“{}: {}”.format(key, field.field[key]) for key in someList])

 

A simpler approach is just append each field key and entry and join these strings into a list and print them.

Cheers,

Joseph

 

From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Andy B.
Sent: Wednesday, November 27, 2019 7:20 AM
To: nvda-addons@nvda-addons.groups.io
Subject: [nvda-addons] Arranging elements of an array

 

Hi,

 

I am trying to arrange elements in an array. This array has font and formatting information such as font, font size, and colors. A user request wanted the foreground and background colors one after the other. Unfortunately, the colors are not one after another. Does anyone have any ideas on how to rearrange elements of an array like this? Here is the code I do have at the moment.

 

@script(description = u"Reports formatting information for an object.")
def script_GetFontInfo(self, gesture):
focus = api.getFocusObject()
formatting = []
if shared.isWebElement(focus):
tree = focus.treeInterceptor
info = tree.makeTextInfo(textInfos.POSITION_ALL)
info.expand(textInfos.UNIT_CHARACTER)
fields = info.getTextWithFields()
for field in fields:
if isinstance (field, textInfos.FieldCommand) and isinstance (field.field, textInfos.FormatField):
for key in field.field:
formatting += [u"{}: {}".format(key, field.field[key])]
message = u"\n".join(formatting)
if getLastScriptRepeatCount() == 0:
ui.message(message)
elif getLastScriptRepeatCount() >= 1:
shared.copyToClipboard(message)
else:
message = u"Only available in web content."
ui.message(message)



--
Derek Riemer
Improving the world one byte at a time!        ⠠⠊⠍⠏⠗⠕⠧⠬ ⠮ ⠸⠺ ⠐⠕ ⠃⠽⠞⠑ ⠁⠞ ⠁ ⠐⠞⠖
•    Accessibility enthusiast.
•    Proud user of the NVDA screen reader.
•    Open source enthusiast.
•    Skier.

•    Personal website: https://derekriemer.com




Andy B.
 

Hi,

I will try picking off the elements of the dictionary in the order I want them to appear in my final output. It seems the easiest method to use.


On Sat, Nov 30, 2019 at 3:25 PM derek riemer <driemer.riemer@...> wrote:
It's best to think of the order you iterate through the field as random. This is because the format fields are stored in a dictionary (a hash table), and the key is hashed down to a value. The order of keys is listed in hash order. This order could change with python versions, and thus you aren't guaranteed to have the same order of color info in the future. I would create a template string with the info you want and grab that info from the field item by item. Alternatively, you could sort the keys of the field (about Theta(n log(n)) or better with pythons sorting. This means the algorithm would take on average n*log2(n) time to complete, where n is the number of items in the field. Then, loop through your field, grab the value, and store it in a string with the key. For the number of items we have in our field, this wouldn't be too bad, and the order is guaranteed. If you want a specific order, you could pass a key function into the algorithm, adding weight to the items you want to sink to the bottom.

On Wed, Nov 27, 2019 at 8:55 AM Joseph Lee <joseph.lee22590@...> wrote:

Hi,

One way (although a bit expensive to calculate) is rearrange the array via key string look up as follows:

  1. Prepare a variable to store the index of the foreground color entry.
  2. In the inner for loop, store the index of the foreground color key right after concatenation (by the way, += is not really a good readable way to append to a list).
  3. When background color key shows up, instead of appending to the formatting list, insert background color information behind the foreground color index via list.insert method (insert it right after foreground color index (so index+1)).
  4. Proceed with iteration (just say “continue”).

 

As for append comment, what you are really doing is creating a list of lists – a simple way to just create a list of strings is just appending a string (list.append(str)). A bit more complex way (and a bit faster) is using list comprehension with conditions like so:

someList = [entry in list if condition]

 

Then build a list of format field keys and rearrange the array directly by using list.index and list.insert. Then all that’s left is build formatting list on the fly like so:

Message = “\n”.join([“{}: {}”.format(key, field.field[key]) for key in someList])

 

A simpler approach is just append each field key and entry and join these strings into a list and print them.

Cheers,

Joseph

 

From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Andy B.
Sent: Wednesday, November 27, 2019 7:20 AM
To: nvda-addons@nvda-addons.groups.io
Subject: [nvda-addons] Arranging elements of an array

 

Hi,

 

I am trying to arrange elements in an array. This array has font and formatting information such as font, font size, and colors. A user request wanted the foreground and background colors one after the other. Unfortunately, the colors are not one after another. Does anyone have any ideas on how to rearrange elements of an array like this? Here is the code I do have at the moment.

 

@script(description = u"Reports formatting information for an object.")
def script_GetFontInfo(self, gesture):
focus = api.getFocusObject()
formatting = []
if shared.isWebElement(focus):
tree = focus.treeInterceptor
info = tree.makeTextInfo(textInfos.POSITION_ALL)
info.expand(textInfos.UNIT_CHARACTER)
fields = info.getTextWithFields()
for field in fields:
if isinstance (field, textInfos.FieldCommand) and isinstance (field.field, textInfos.FormatField):
for key in field.field:
formatting += [u"{}: {}".format(key, field.field[key])]
message = u"\n".join(formatting)
if getLastScriptRepeatCount() == 0:
ui.message(message)
elif getLastScriptRepeatCount() >= 1:
shared.copyToClipboard(message)
else:
message = u"Only available in web content."
ui.message(message)



--
Derek Riemer
Improving the world one byte at a time!        ⠠⠊⠍⠏⠗⠕⠧⠬ ⠮ ⠸⠺ ⠐⠕ ⠃⠽⠞⠑ ⠁⠞ ⠁ ⠐⠞⠖
•    Accessibility enthusiast.
•    Proud user of the NVDA screen reader.
•    Open source enthusiast.
•    Skier.

•    Personal website: https://derekriemer.com