How to Add a Suffix (Or Prefix) Elements of an Existing List

How do I add a suffix (or prefix) elements of an existing list?

Use lapply and paste0

> lapply(myList, paste0, ".t0")
$list1
[1] "item1.t0" "item2.t0"

$list2
[1] "item3.t0" "item4.t0"

How to add prefix to all the elements of List efficiently?

For one liners, use Java 8 Streams :

List<String> paths = DATA_TYPE.stream().map(c -> flow.value() + c.value()).collect(Collectors.toList());

If you must produce a LinkedList, you should use a different Collector.

Add a suffix to each dataframe in a list?

If we need to automatically get a named list, use mget with a pattern argument in the ls. In the below code, we are getting the value of objects with names that start (^) with substring 'df' followed by one or more digits (\\d+) till the end ($) of the string.

lst1 <- mget(ls(pattern = '^df\\d+$'))

Now, if we use list2env on the list created, it would update the same objects in the global environment

list2env(lapply(lst1, transform, new = V1 + 3), .GlobalEnv)

And if we need to create new objects, just change the name of the lst1

names(lst1) <- paste0(names(lst1), "_2018")
list2env(lapply(lst1, transform, new = V1 + 3), .GlobalEnv)

How to add prefix to list items only if prefix is not there already?

Try this.

['p' + x for x in l if x[0] != 'p']

Sorry, that gives the same as yours, if you want all three then try.

['p' + x if x[0] != 'p' else x for x in l]

How to add a suffix (or prefix) to each column name?

You can use a list comprehension:

df.columns = [str(col) + '_x' for col in df.columns]

There are also built-in methods like .add_suffix() and .add_prefix() as mentioned in another answer.

Duplicate strings in a list and add integer suffixes to newly added ones

yield

You can use a generator for an elegant solution. At each iteration, yield twice—once with the original element, and once with the element with the added suffix.

The generator will need to be exhausted; that can be done by tacking on a list call at the end.

def transform(l):
for i, x in enumerate(l, 1):
yield x
yield f'{x}_{i}' # {}_{}'.format(x, i)

You can also re-write this using the yield from syntax for generator delegation:

def transform(l):
for i, x in enumerate(l, 1):
yield from (x, f'{x}_{i}') # (x, {}_{}'.format(x, i))

out_l = list(transform(l))
print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']

If you're on versions older than python-3.6, replace f'{x}_{i}' with '{}_{}'.format(x, i).

Generalising

Consider a general scenario where you have N lists of the form:

l1 = [v11, v12, ...]
l2 = [v21, v22, ...]
l3 = [v31, v32, ...]
...

Which you would like to interleave. These lists are not necessarily derived from each other.

To handle interleaving operations with these N lists, you'll need to iterate over pairs:

def transformN(*args):
for vals in zip(*args):
yield from vals

out_l = transformN(l1, l2, l3, ...)

Sliced list.__setitem__

I'd recommend this from the perspective of performance. First allocate space for an empty list, and then assign list items to their appropriate positions using sliced list assignment. l goes into even indexes, and l' (l modified) goes into odd indexes.

out_l = [None] * (len(l) * 2)
out_l[::2] = l
out_l[1::2] = [f'{x}_{i}' for i, x in enumerate(l, 1)] # [{}_{}'.format(x, i) ...]

print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']

This is consistently the fastest from my timings (below).

Generalising

To handle N lists, iteratively assign to slices.

list_of_lists = [l1, l2, ...]

out_l = [None] * len(list_of_lists[0]) * len(list_of_lists)
for i, l in enumerate(list_of_lists):
out_l[i::2] = l

zip + chain.from_iterable

A functional approach, similar to @chrisz' solution. Construct pairs using zip and then flatten it using itertools.chain.

from itertools import chain
# [{}_{}'.format(x, i) ...]
out_l = list(chain.from_iterable(zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)])))

print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']

iterools.chain is widely regarded as the pythonic list flattening approach.

Generalising

This is the simplest solution to generalise, and I suspect the most efficient for multiple lists when N is large.

list_of_lists = [l1, l2, ...]
out_l = list(chain.from_iterable(zip(*list_of_lists)))

Performance

Let's take a look at some perf-tests for the simple case of two lists (one list with its suffix). General cases will not be tested since the results widely vary with by data.

Sample Image

Benchmarking code, for reference.

Functions

def cs1(l):
def _cs1(l):
for i, x in enumerate(l, 1):
yield x
yield f'{x}_{i}'

return list(_cs1(l))

def cs2(l):
out_l = [None] * (len(l) * 2)
out_l[::2] = l
out_l[1::2] = [f'{x}_{i}' for i, x in enumerate(l, 1)]

return out_l

def cs3(l):
return list(chain.from_iterable(
zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)])))

def ajax(l):
return [
i for b in [[a, '{}_{}'.format(a, i)]
for i, a in enumerate(l, start=1)]
for i in b
]

def ajax_cs0(l):
# suggested improvement to ajax solution
return [j for i, a in enumerate(l, 1) for j in [a, '{}_{}'.format(a, i)]]

def chrisz(l):
return [
val
for pair in zip(l, [f'{k}_{j+1}' for j, k in enumerate(l)])
for val in pair
]

How to add prefix and suffix to a string in python

You can concatenate those onto the string using +.

For example (for Python 2):

print "^"+str1+"$"

Or without + using f-strings in Python 3:

print( f“^{str}$” )

Or if you want to add a prefix to every string in a list:

strings = ['hello', 1, 'bye']
decoratedstrings = [f"^{s}$" for s in strings]

result:

['^hello$', '^1$', '^bye$']

Add prefix and suffix to $@ in bash

I would use shell [ parameter expansion ] for this

$ set -- one two three
$ echo "$@"
one two three
$ set -- "${@/#/pre}" && set -- "${@/%/post}"
$ echo "$@"
preonepost pretwopost prethreepost

Notes

  • The # matches the beginning
  • The % matches the end
  • Using double quotes around ${@} considers each element as a separate word. so replacement happens for every positional parameter

How to join a list elements by ',' using streams with ' as prefix and suffix too

You can actually use Collectors.joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix) and you can look here for the API.

String values = list.stream().collect(Collectors.joining("','", "'", "'"));

Add prefix and suffix to Collectors.joining() only if there are multiple items present

Yes, this is possible using a custom Collector instance that will use an anonymous object with a count of items in the stream and an overloaded toString() method:

public String format(Stream<String> stream) {
return stream.collect(
() -> new Object() {
StringJoiner stringJoiner = new StringJoiner(",");
int count;

@Override
public String toString() {
return count == 1 ? stringJoiner.toString() : "[" + stringJoiner + "]";
}
},
(container, currentString) -> {
container.stringJoiner.add(currentString);
container.count++;
},
(accumulatingContainer, currentContainer) -> {
accumulatingContainer.stringJoiner.merge(currentContainer.stringJoiner);
accumulatingContainer.count += currentContainer.count;
}
).toString();
}

Explanation

Collector interface has the following methods:

public interface Collector<T,A,R> {
Supplier<A> supplier();
BiConsumer<A,T> accumulator();
BinaryOperator<A> combiner();
Function<A,R> finisher();
Set<Characteristics> characteristics();
}

I will omit the last method as it is not relevant for this example.

There is a collect() method with the following signature:

<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);

and in our case it would resolve to:

<Object> Object collect(Supplier<Object> supplier,
BiConsumer<Object, ? super String> accumulator,
BiConsumer<Object, Object> combiner);
  • In the supplier, we are using an instance of StringJoiner (basically the same thing that Collectors.joining() is using).
  • In the accumulator, we are using StringJoiner::add() but we increment the count as well
  • In the combiner, we are using StringJoiner::merge() and add the count to the accumulator
  • Before returning from format() function, we need to call toString() method to wrap our accumulated StringJoiner instance in [] (or leave it as is is, in case of a single-element stream

The case for an empty case could also be added, I left it out in order not to make this collector more complicated.



Related Topics



Leave a reply



Submit