Python Iterating an Array - arrays

I have been trying to iterate through an array.
below is the code.
x = ['lemon', 'tea', 'water', ]
def randomShuffle (arr,n):
from random import choices
newList=[]
for item in arr:
r=choices(arr, k=n)
if r.count(item) <= 2:
newList.append(item)
return (newList)
i would like to know the logic for writing it please.
thank you all

Use a while loop: if every item is to appear twice, then teh resulting array should be twice the length of the input one.
And of course check not to add the same item more than twice in the result ;)
Choices return a list of size 1, so I use [0] to get the element
xx = ["a", "b", "c"]
def my_function(x):
res = []
while len(res) < len(x) * 2:
c = choices(x)[0]
if res.count(c) < 2:
res.append(c)
return res
my_function(xx)
> ['c', 'c', 'a', 'b', 'a', 'b']
my_function(xx)
> ['a', 'b', 'b', 'a', 'c', 'c']

Related

If a list1 containing some elements of list2. Does list1 also changes if list2 changes?

This is what I am trying to create.
list2 =[1,2,3];
list1= [list2[0],list2[1]];
list2[0]=2;
print(list1);
I want the output to be [2,2] not [1,2]
Integers in Python are immutable. This is the behaviour you are expecting with the list, but it is not possible. Consider this example:
x = 0
y = 0
print(id(x), id(y))
y = 1
print(id(y))
Output:
94583099374048 94583099374048
94583099374080
Whereas lists are mutable:
a_list = ["a",
"b",
"c",
"d",
"e",
"f"
]
b_list = a_list
print("a list id before update", id(a_list))
print("b list id before update", id(b_list))
a_list += ["g"]
print("a list after update", a_list)
print("b list after update", b_list)
print("a list id after update", id(a_list))
print("b list id after update", id(b_list,))
Output:
a list id before update 139734649089472
b list id before update 139734649089472
a list after update ['a', 'b', 'c', 'd', 'e', 'f', 'g']
b list after update ['a', 'b', 'c', 'd', 'e', 'f', 'g']
a list id after update 139734649089472
b list id after update 139734649089472
This explains the behaviour you are seeing. list1 and list2 are stored in separate memory locations because you haven't equated the lists themselves. And therefore there is no link between list1[0] and list2[0].
Note: id() returns the memory address of an object.

Best way to generate all combinations in array that contain certain element in it

I know that I can easily get all the combinations, but is there a way to only get the ones that contain certain element of the list? I'll give an example.
Lets say I have
arr = ['a','b','c','d']
I want to get all combinations with length (n) containing 'a', for example, if n = 3:
[a, b, c]
[a, b, d]
[a, c, d]
I want to know if there is a better way to get it without generating all combinations. Any help would be appreciated.
I would proceed as follow:
Remove 'a' from the array
Generate all combinations of 2 elements from the reduced array
For each combination, insert the 'a' in all three possible places
You can use combination of itertools and list comprehension. Like:
import itertools
import itertools
arr = ['a', 'b', 'c', 'd']
temp = itertools.combinations(arr, 3)
result = [list(i) for i in list(temp) if 'a' in i]
print(result)
output:
[['a', 'b', 'c'], ['a', 'b', 'd'], ['a', 'c', 'd']]

Get indices of strings in an array

I have an array in numpy which looks like this:
myarray = ['a', 'b', 'c', 'd', 'e', 'f']
I would like to return an array of indices for 'b', 'c', 'd' which looks like this:
myind = [1,2,3]
I need this indices array later to use it in a loop. I am using Python 2.7. Thanks folks
You can use np.searchsorted -
In [61]: myarray = np.array(['a', 'b', 'c', 'd', 'e', 'f'])
In [62]: search = np.array(['b', 'c', 'd'])
In [63]: np.searchsorted(myarray, search)
Out[63]: array([1, 2, 3])
If myarray is not alphabetically sorted, we need to use the additional argument sorter with it, like so -
In [64]: myarray = np.array(['a', 'd', 'b', 'e', 'c', 'f'])
In [65]: search = np.array(['b', 'c', 'd'])
In [67]: sidx = np.argsort(myarray)
In [69]: sidx[np.searchsorted(myarray, search, sorter=sidx)]
Out[69]: array([2, 4, 1])
If your array does not contain any duplicates then np.searchsorted should do the trick. if your array contains duplicates then you have to use np.argwhere
Examples:
input_array = np.array(['a','b','c','d','e','f','a'])
search = np.array(['a','b','c'])
np.searchsorted(input_array, search)
output >> array([0, 1, 2])
np.argwhere(input_array == 'a')
output >> array([[0],[6]])
For a more general solution you can do
np.concatenate( (np.argwhere(input_array == 'a') ,
np.argwhere(input_array == 'b'),
np.argwhere(input_array == 'c') ) )
output >> array([[0],[6],[1],[2]])

Remove one object from an array with multiple matching objects

I have an array:
array = ['a', 'b', 'c', 'a', 'b', 'a', 'a']
sorted, just to make it easier to look at:
array = ['a', 'a', 'a', 'a', 'b', 'b', 'c']
I want to remove, for example, three of the a's. array.delete('a') removes every a.
The following code 'works' but I think you'll agree it's absolutely hideous.
new_array = array.sort.join.sub!('aaa', '').split(//)
How do I do this more cleanly?
To give a bit more information on what I'm doing here, I have some strings being pushed into an array asynchronously. Those strings can be (and often are) identical to each other. If there are a certain number of those matching strings, an action is triggered, the matching object is removed (like Tetris, I guess), and the process continues.
Before the following code is run, array could be ['a', 'a', 'a', 'b']:
while array.count(product[:name]) >= product[:quantity]
# trigger an event
product[:quantity].times do
array.slice!(array.index(product[:name]))
end
end
assuming that product[:name] is a and product[:quantity] is 3, after the code above runs, array should be ['b'].
I think you have an XY-problem. Instead of an array, you should use a hash with number of occurrences as the value.
hash = Hash.new(0)
When you want to add an entity, you should do:
hash["a"] += 1
If you want to limit the number to a certain value, say k, then do:
hash["a"] += 1 unless hash["a"] == k
slice may be the thing you're looking for:
3.times {array.slice!(array.index('a'))}
If you want to maintain, or convert, an array so it only one instance of each element, you can use uniq or a Set instead of an array.
array = ['a', 'b', 'c', 'a', 'b', 'a', 'a']
array.uniq # => ["a", "b", "c"]
require 'set'
array.to_set # => #<Set: {"a", "b", "c"}>
A Set will automatically maintain the uniqueness of all the elements for you, which is useful if you're going to have a huge number of potentially repetitive elements and don't want to accumulate them in memory before doing a uniq on them.
#sawa mentioned that this looks like an "XY problem", and I agree.
The source of the problem is using an array instead of a hash as your basic container. An array is good when you have a queue or list of things to process in order but it's horrible when you need to keep track of the count of things, because you have to walk that array to find out how many of a certain thing you have. There are ways to coerce the information you want out of an array when you get the array as your source.
Since it looks like he identified the real problem, here are some building blocks to use around the problem.
If you have an array and want to figure out how many different elements there are, and their count:
array = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c']
array_count = array.group_by { |i| i }.map{ |k, v| [k, v.size] }.to_h
# => {"a"=>4, "b"=>2, "c"=>2}
From that point it's easy to find out which ones exceed a certain count:
array_count.select{ |k, v| v >= 3 } # => {"a"=>4}
For a quick way to remove all elements of something from the array, after processing you can use a set "difference" operation:
array = ['a', 'a', 'a', 'a', 'b', 'b', 'c']
array -= ['a']
# => ["b", "b", "c", "c"]
or delete_if:
array.delete_if { |i| i == 'a' }
array # => ["b", "b", "c"]

Algorithm to reorder multiple non-adjacent elements in array to specific index

I've been trying to rack my head over this but it's just not working.
I'm using some proprietary technology that only allows the move of a single element at a time. Super annoying. Think of it as list.moveRow(before, after).
So imagine a todo list with 10 items in it: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
What I want to do is reorder multiple items in there,
so say I select items 2, 6, 7, and 8.
Then I drag and drop to position 4.
The idea is that the elements would now be in order: 1, 3, 2, 6, 7, 8, 4, 5, 9, 10.
Is there a simple way to do this? I tried using extra variables to keep track of offsets due to an element moved that throws off the index, but it's super messy. :(
It really depends on the language.
Supposing you have a simple way to get isSelected() for each item, the simplest and most generic seems to be to build a new array as a list (that is adding from the first index to the last one) :
add in order the non selected items until position of insert
add the selected items
add the remaining unselected items
And after that replace old array.
In pseudo code :
func(int[] items, bool[] isselected, int insertpos) {
newitems = new int[items.length]
i=0
for (j=0; j<items.length; j++) {
if j==insertpos {
for (k=0; k<items.length; k++) {
if isselected[k] {
newitems[i++] = items[k]
}
}
} else if !isselected[j] {
newitems[i++] = items[j]
}
}
return newitems
}
If you want high performance and in place modification... that's another matter...
Sat down and wrote it out, and came up with a reasonable solution. This seems to work fine:
// Reorder list
function reorder(items, index)
{
// When we move, we have to account for previously moved rows too
// Go from bottom-most selected row first to preserve order
for (var i = items.length - 1, itemOffset = 0, indexOffset = 0; i >= 0; --i)
{
// Move
list.moveRow(items[i] + itemOffset, index + indexOffset);
// Change offsets based on location
// If next row index is after target index, add to row offset
if (i-1 >= 0 && items[i-1] >= index) {
itemOffset++;
} else { // If next index is before target, subtract from target
itemOffset= 0;
indexOffset--;
}
}
}
I wish I found this sooner. Anyhow, in modern JS it is possible (and desired!) to do this without conditionals, and there is an elegant algorithm which allows for that by using placeholders.
Specifically we can use a Symbol as a stand-in for elements that are traveling within the ordered set. This way the index arithmetic is eliminated (and with it a slew of conditionals and places where off-by-one errors fester).
Works basically like this:
withGroupRepositioned(["a", "b", "c", "d"], ["a", "b"], 0) // [ 'a', 'b', 'c', 'd' ]
withGroupRepositioned(["a", "b", "c", "d"], ["a", "b"], 1) // [ 'a', 'b', 'c', 'd' ]
withGroupRepositioned(["a", "b", "c", "d"], ["a", "b"], 2) // [ 'a', 'b', 'c', 'd' ]
withGroupRepositioned(["a", "b", "c", "d"], ["a", "b"], 3) // [ 'c', 'a', 'b', 'd' ]
withGroupRepositioned(["a", "b", "c", "d"], ["b", "a"], 2) // [ 'b', 'a', 'c', 'd' ]
withGroupRepositioned(["a", "b", "c", "d"], ["b", "a"], 3) // [ 'c', 'b', 'a', 'd' ]
withGroupRepositioned(["a", "b", "c", "d"], ["a", "c"], 4) // [ 'b', 'd', 'a', 'c' ]
and the entire function is:
const PLACEHOLDER = Symbol();
function withGroupRepositioned(inOrderedSet, valuesToReposition, toIndex) {
// Do not damage the given set
const cpy = [].concat(inOrderedSet);
// Step 1. Replace all traveling elements with placeholders, in place.
valuesToReposition.forEach((v) => cpy[cpy.indexOf(v)] = PLACEHOLDER);
// Step 2. Reinsert values as a group, where we want them.
cpy.splice(toIndex, 0, ...valuesToReposition);
// Step 3. Remove placeholders.
return cpy.filter((v) => v !== PLACEHOLDER);
}
The first array copy operation can be removed if you want to perform the rearrangement in-place.

Resources