Python:通过连接大小将字符串列表拆分为更小块的有效方法
Python: Efficient way to split list of strings into smaller chunks by concatenated size
我正在通过其 google-api-python-client
通过批量请求与 Google API 通信。在批处理请求中存在限制:
- 一个批量请求不能超过1000个请求,
- 批量请求的负载中不能超过 1MB。
我在一个列表中有随机数量的随机长度字符串,我需要从中构造一个批处理请求,同时牢记上述限制。
有谁知道有效构建可提交给 Google API 的原始列表块的好方法? 'efficiently' 我的意思是,不遍历第一部分中的所有元素(计算有效负载大小)。
到目前为止,这就是我的想法:最多取 1000 件物品,构建请求,查看负载大小。如果大于1M,取500,看大小。如果有效负载更大,则取前 250 个项目。如果有效负载较小,则取 750 个项目。等等,你明白了逻辑。这样一来,与在每次添加后检查它时构建有效载荷相比,可以通过更少的迭代获得适量的元素。
我真的不想重新发明轮子,所以如果有人知道有效的builtin/module,请告诉我。
当您向实例化的 BatchHttpRequest 添加了正确数量的请求后,可以通过调用 _serialize_request 来计算正文负载大小。
另请参阅 Python API Client Library documentation 进行批量请求。
好吧,看来我创造了解决这个问题的东西,这是 python 中的想法草稿:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import random
import string
import sys
MAX_LENGTH = 20
MAX_SIZE = 11111
def get_random():
return ''.join([
random.choice(string.ascii_letters) for i in range(
random.randrange(10, 1000))])
def get_random_list():
return [get_random() for i in range(random.randrange(50, 1000))]
def get_str_length(rnd_list, item_idx):
return len(''.join(rnd_list[:item_idx]))
rnd_list = get_random_list()
def calculate_ideal_amount(rnd_list):
list_bounds = {
'first': 1,
'last': len(rnd_list)
}
print ('ORIG_SIZE: %s, ORIG_LEN: %s' % (
get_str_length(rnd_list, len(rnd_list)), len(rnd_list)))
if get_str_length(rnd_list, list_bounds['first']) > MAX_SIZE:
return 0
if get_str_length(rnd_list, list_bounds['last']) <= MAX_SIZE and \
list_bounds['last'] <= MAX_LENGTH:
return list_bounds['last']
while True:
difference = round((list_bounds['last'] - list_bounds['first']) / 2)
middle_item_idx = list_bounds['first'] + difference
str_len = get_str_length(
rnd_list, middle_item_idx)
print(
'MAX_SIZE: %s, list_bounds: %s, '
'middle_item_idx: %s, diff: %s, str_len: %s,' % (
MAX_SIZE, list_bounds, middle_item_idx, difference, str_len))
# sys.stdin.readline()
if str_len > MAX_SIZE:
list_bounds['last'] = middle_item_idx
continue
if middle_item_idx > MAX_LENGTH:
return MAX_LENGTH
list_bounds['first'] = middle_item_idx
if difference == 0:
if get_str_length(rnd_list, list_bounds['last']) <= MAX_SIZE:
if list_bounds['last'] > MAX_LENGTH:
return MAX_LENGTH
return list_bounds['last']
return list_bounds['first']
ideal_idx = calculate_ideal_amount(rnd_list)
print (
len(rnd_list), get_str_length(rnd_list, len(rnd_list)),
get_str_length(rnd_list, ideal_idx), ideal_idx,
get_str_length(rnd_list, ideal_idx + 1))
此代码与我试图描述的完全相同,通过查找和修改列表的边界,同时测量其返回的(连接的)大小,然后返回应按顺序切片的列表的索引以获得最有效的字符串大小。这种方法避免了逐一编译和测量列表的 CPU 开销。 运行 此代码将显示它在列表中执行的迭代。
get_str_length
、列表等函数可以替换成使用API客户端中相应的功能,但这是后面的大概思路。
但是代码并非万无一失,解决方案应该遵循这些思路。
我正在通过其 google-api-python-client
通过批量请求与 Google API 通信。在批处理请求中存在限制:
- 一个批量请求不能超过1000个请求,
- 批量请求的负载中不能超过 1MB。
我在一个列表中有随机数量的随机长度字符串,我需要从中构造一个批处理请求,同时牢记上述限制。
有谁知道有效构建可提交给 Google API 的原始列表块的好方法? 'efficiently' 我的意思是,不遍历第一部分中的所有元素(计算有效负载大小)。
到目前为止,这就是我的想法:最多取 1000 件物品,构建请求,查看负载大小。如果大于1M,取500,看大小。如果有效负载更大,则取前 250 个项目。如果有效负载较小,则取 750 个项目。等等,你明白了逻辑。这样一来,与在每次添加后检查它时构建有效载荷相比,可以通过更少的迭代获得适量的元素。
我真的不想重新发明轮子,所以如果有人知道有效的builtin/module,请告诉我。
当您向实例化的 BatchHttpRequest 添加了正确数量的请求后,可以通过调用 _serialize_request 来计算正文负载大小。
另请参阅 Python API Client Library documentation 进行批量请求。
好吧,看来我创造了解决这个问题的东西,这是 python 中的想法草稿:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import random
import string
import sys
MAX_LENGTH = 20
MAX_SIZE = 11111
def get_random():
return ''.join([
random.choice(string.ascii_letters) for i in range(
random.randrange(10, 1000))])
def get_random_list():
return [get_random() for i in range(random.randrange(50, 1000))]
def get_str_length(rnd_list, item_idx):
return len(''.join(rnd_list[:item_idx]))
rnd_list = get_random_list()
def calculate_ideal_amount(rnd_list):
list_bounds = {
'first': 1,
'last': len(rnd_list)
}
print ('ORIG_SIZE: %s, ORIG_LEN: %s' % (
get_str_length(rnd_list, len(rnd_list)), len(rnd_list)))
if get_str_length(rnd_list, list_bounds['first']) > MAX_SIZE:
return 0
if get_str_length(rnd_list, list_bounds['last']) <= MAX_SIZE and \
list_bounds['last'] <= MAX_LENGTH:
return list_bounds['last']
while True:
difference = round((list_bounds['last'] - list_bounds['first']) / 2)
middle_item_idx = list_bounds['first'] + difference
str_len = get_str_length(
rnd_list, middle_item_idx)
print(
'MAX_SIZE: %s, list_bounds: %s, '
'middle_item_idx: %s, diff: %s, str_len: %s,' % (
MAX_SIZE, list_bounds, middle_item_idx, difference, str_len))
# sys.stdin.readline()
if str_len > MAX_SIZE:
list_bounds['last'] = middle_item_idx
continue
if middle_item_idx > MAX_LENGTH:
return MAX_LENGTH
list_bounds['first'] = middle_item_idx
if difference == 0:
if get_str_length(rnd_list, list_bounds['last']) <= MAX_SIZE:
if list_bounds['last'] > MAX_LENGTH:
return MAX_LENGTH
return list_bounds['last']
return list_bounds['first']
ideal_idx = calculate_ideal_amount(rnd_list)
print (
len(rnd_list), get_str_length(rnd_list, len(rnd_list)),
get_str_length(rnd_list, ideal_idx), ideal_idx,
get_str_length(rnd_list, ideal_idx + 1))
此代码与我试图描述的完全相同,通过查找和修改列表的边界,同时测量其返回的(连接的)大小,然后返回应按顺序切片的列表的索引以获得最有效的字符串大小。这种方法避免了逐一编译和测量列表的 CPU 开销。 运行 此代码将显示它在列表中执行的迭代。
get_str_length
、列表等函数可以替换成使用API客户端中相应的功能,但这是后面的大概思路。
但是代码并非万无一失,解决方案应该遵循这些思路。