Print the first, second occurred character in a list - python

I working on a simple algorithm which prints the first character who occurred twice or more.
for eg:
string ='abcabc'
output = a
string = 'abccba'
output = c
string = 'abba'
output = b
what I have done is:
string = 'abcabc'
s = []
for x in string:
if x in s:
print(x)
break
else:
s.append(x)
output: a
But its time complexity is O(n^2), how can I do this in O(n)?

Change s = [] to s = set() (and obviously the corresponding append to add). in over set is O(1), unlike in over list which is sequential.
Alternately, with regular expressions (O(n^2), but rather fast and easy):
import re
match = re.search(r'(.).*\1', string)
if match:
print(match.group(1))
The regular expression (.).*\1 means "any character which we'll remember for later, any number of intervening characters, then the remembered character again". Since regexp is scanned left-to-right, it will find a in "abba" rather than b, as required.

Use dictionaries
string = 'abcabc'
s = {}
for x in string:
if x in s:
print(x)
break
else:
s[x] = 0
or use sets
string = 'abcabc'
s = set()
for x in string:
if x in s:
print(x)
break
else:
s.add(x)
both dictionaries and sets use indexing and search in O(1)

Related

How do i make the program print specific letters in this specific format i give to it?

so i need to code a program which, for example if given the input 3[a]2[b], prints "aaabb" or when given 3[ab]2[c],prints "abababcc"(basicly prints that amount of that letter in the given order). i tried to use a for loop to iterate the first given input and then detect "[" letters in it so it'll know that to repeatedly print but i don't know how i can make it also understand where that string ends
also this is where i could get it to,which probably isnt too useful:
string=input()
string=string[::-1]
bulundu=6
for i in string:
if i!="]":
if i!="[":
lst.append(i)
if i=="[":
break
The approach I took is to remove the brackets, split the items into a list, then walk the list, and if the item is a number, add that many repeats of the next item to the result for output:
import re
data = "3[a]2[b]"
# Remove brackets and convert to a list
data = re.sub(r'[\[\]]', ' ', data).split()
result = []
for i, item in enumerate(data):
# If item is a number, print that many of the next item
if item.isdigit():
result.append(data[i+1] * int(item))
print(''.join(result))
# aaabb
A different approach, inspired by Subbu's use of re.findall. This approach finds all 'pairs' of numbers and letters using match groups, then multiplies them to produce the required text:
import re
data = "3[a]2[b]"
matches = re.findall('(\d+)\[([a-zA-Z]+)\]',data)
# [(3, 'a'), (2, 'b')]
for x in matches:
print(x[1] * int(x[0]), end='')
#aaabb
Lenghty and documented version using NO regex but simple string and list manipulation:
first split the input into parts that are numbers and texts
then recombinate them again
I opted to document with inline comments
This could be done like so:
# testcases are tuples of input and correct result
testcases = [ ("3[a]2[b]","aaabb"),
("3[ab]2[c]","abababcc"),
("5[12]6[c]","1212121212cccccc"),
("22[a]","a"*22)]
# now we use our algo for all those testcases
for inp,res in testcases:
split_inp = [] # list that takes the splitted values of the input
num = 0 # accumulator variable for more-then-1-digit numbers
in_text = False # bool that tells us if we are currently collecting letters
# go over all letters : O(n)
for c in inp:
# when a [ is reached our num is complete and we need to store it
# we collect all further letters until next ] in a list that we
# add at the end of your split_inp
if c == "[":
split_inp.append(num) # add the completed number
num = 0 # and reset it to 0
in_text = True # now in text
split_inp.append([]) # add a list to collect letters
# done collecting letters
elif c == "]":
in_text = False # no longer collecting, convert letters
split_inp[-1] = ''.join(split_inp[-1]) # to text
# between [ and ] ... simply add letter to list at end
elif in_text:
split_inp[-1].append(c) # add letter
# currently collecting numbers
else:
num *= 10 # increase current number by factor 10
num += int(c) # add newest number
print(repr(inp), split_inp, sep="\n") # debugging output for parsing part
# now we need to build the string from our parsed data
amount = 0
result = [] # intermediate list to join ['aaa','bb']
# iterate the list, if int remember it, it text, build composite
for part in split_inp:
if isinstance(part, int):
amount = part
else:
result.append(part*amount)
# join the parts
result = ''.join(result)
# check if all worked out
if result == res:
print("CORRECT: ", result + "\n")
else:
print (f"INCORRECT: should be '{res}' but is '{result}'\n")
Result:
'3[a]2[b]'
[3, 'a', 2, 'b']
CORRECT: aaabb
'3[ab]2[c]'
[3, 'ab', 2, 'c']
CORRECT: abababcc
'5[12]6[c]'
[5, '12', 6, 'c']
CORRECT: 1212121212cccccc
'22[a]'
[22, 'a']
CORRECT: aaaaaaaaaaaaaaaaaaaaaa
This will also handle cases of '5[12]' wich some of the other solutions wont.
You can capture both the number of repetitions n and the pattern to repeat v in one go using the described pattern. This essentially matches any sequence of digits - which is the first group we need to capture, reason why \d+ is between brackets (..) - followed by a [, followed by anything - this anything is the second pattern of interest, hence it is between backets (...) - which is then followed by a ].
findall will find all these matches in the passed line, then the first match - the number - will be cast to an int and used as a multiplier for the string pattern. The list of int(n) * v is then joined with an empty space. Malformed patterns may throw exceptions or return nothing.
Anyway, in code:
import re
pattern = re.compile("(\d+)\[(.*?)\]")
def func(x): return "".join([v*int(n) for n,v in pattern.findall(x)])
print(func("3[a]2[b]"))
print(func("3[ab]2[c]"))
OUTPUT
aaabb
abababcc
FOLLOW UP
Another solution which achieves the same result, without using regular expression (ok, not nice at all, I get it...):
def func(s): return "".join([int(x[0])*x[1] for x in map(lambda x:x.split("["), s.split("]")) if len(x) == 2])
I am not much more than a beginner and looking at the other answers, I thought understanding regex might be a challenge for a new contributor such as yourself since I myself haven't really dealt with regex.
The beginner friendly way to do this might be to loop through the input string and use string functions like isnumeric() and isalpha()
data = "3[a]2[b]"
chars = []
nums = []
substrings = []
for i, char in enumerate(data):
if char.isnumeric():
nums.append(char)
if char.isalpha():
chars.append(char)
for i, char in enumerate(chars):
substrings.append(char * int(nums[i]))
string = "".join(substrings)
print(string)
OUTPUT:
aaabb
And on trying different values for data:
data = "0[a]2[b]3[p]"
OUTPUT bbppp
data = "1[a]1[a]2[a]"
OUTPUT aaaa
NOTE: In case you're not familiar with the above functions, they are string functions, which are fairly self-explanatory. They are used as <your_string_here>.isalpha() which returns true if and only if the string is an alphabet (whitespace, numerics, and symbols return false
And, similarly for isnumeric()
For example,
"]".isnumeric() and "]".isalpha() return False
"a".isalpha() returns True
IF YOU NEED ANY CLARIFICATION ON A FUNCTION USED, PLEASE DO NOT HESITATE TO LEAVE A COMMENT

How do I check if the next item in a string is the alphabetical successor of the one before? + Inverse

I'm trying to compress a string in a way that any sequence of letters in strict alphabetical order is swapped with the first letter plus the length of the sequence.
For example, the string "abcdefxylmno", would become: "a6xyl4"
Single letters that aren't in order with the one before or after just stay the way they are.
How do I check that two letters are successors (a,b) and not simply in alphabetical order (a,c)? And how do I keep iterating on the string until I find a letter that doesn't meet this requirement?
I'm also trying to do this in a way that makes it easier to write an inverse function (that given the result string gives me back the original one).
EDIT :
I've managed to get the function working, thanks to your suggestion of using the alphabet string as comparison; now I'm very much stuck on the inverse function: given "a6xyl4" expand it back into "abcdefxylmno".
After quite some time I managed to split the string every time there's a number and I made a function that expands a 2 char string, but it fails to work when I use it on a longer string:
from string import ascii_lowercase as abc
def subString(start,n):
L=[]
ind = abc.index(start)
newAbc = abc[ind:]
for i in range(len(newAbc)):
while i < n:
L.append(newAbc[i])
i+=1
res = ''.join(L)
return res
def unpack(S):
for i in range(len(S)-1):
if S[i] in abc and S[i+1] not in abc:
lett = str(S[i])
num = int(S[i+1])
return subString(lett,num)
def separate(S):
lst = []
for i in S:
lst.append(i)
for el in lst:
if el.isnumeric():
ind = lst.index(el)
lst.insert(ind+1,"-")
a = ''.join(lst)
L = a.split("-")
if S[-1].isnumeric():
L.remove(L[-1])
return L
else:
return L
def inverse(S):
L = separate(S)
for i in L:
return unpack(i)
Each of these functions work singularly, but inverse(S) doesn't output anything. What's the mistake?
You can use the ord() function which returns an integer representing the Unicode character. Sequential letters in alphabetical order differ by 1. Thus said you can implement a simple funtion:
def is_successor(a,b):
# check for marginal cases if we dont ensure
# input restriction somewhere else
if ord(a) not in range(ord('a'), ord('z')) and ord(a) not in range(ord('A'),ord('Z')):
return False
if ord(b) not in range(ord('a'), ord('z')) and ord(b) not in range(ord('A'),ord('Z')):
return False
# returns true if they are sequential
return ((ord(b) - ord(a)) == 1)
You can use chr(int) method for your reversing stage as it returns a string representing a character whose Unicode code point is an integer given as argument.
This builds on the idea that acceptable subsequences will be substrings of the ABC:
from string import ascii_lowercase as abc # 'abcdefg...'
text = 'abcdefxylmno'
stack = []
cache = ''
# collect subsequences
for char in text:
if cache + char in abc:
cache += char
else:
stack.append(cache)
cache = char
# if present, append the last sequence
if cache:
stack.append(cache)
# stack is now ['abcdef', 'xy', 'lmno']
# Build the final string 'a6x2l4'
result = ''.join(f'{s[0]}{len(s)}' if len(s) > 1 else s for s in stack)

How to separate number and ascii character from string?

Let me keep it simple,
I have a string that I want it from "10fo22baar" into ["1022","fobaar"] or ["10","fo","22","baar"]
Is there a way to do something like that in Python 3 or 2?
Part 1: You can use filter with str.isdigit() to filter numeric characters as:
>>> my_str = "10fo22baar"
>>> ''.join(filter(str.isdigit, my_str))
'1022'
To get non-numeric, you can use itertools.filterfalse():
>>> from itertools import filterfalse
>>> ''.join(filterfalse(str.isdigit, my_str))
'fobaar'
# OR, for older python versions, use list comprehension:
# ''.join(c for c in my_str if not c.isdigit())
Store above values in list to get list of your desired format.
Alternatively, you can also use regex to filter out digits and alphabets into separate lists as:
import re
my_str = "10fo22baar"
# - To extract digits, use expressions as "\d+"
# - To extract alphabets, use expressions as "[a-zA-Z]+"
digits = ''.join(re.findall('\d+', my_str))
# where `digits` variable will hold string:
# '1022'
alphabets = ''.join(re.findall('[a-zA-Z]+', my_str))
# where `alphabets` variable will hold string:
# 'fobaar'
# Create your desired list from above variables:
# my_list = [digits, alphabets]
You can simplify above logic in one-line as:
my_regex = ['\d+', '[a-zA-Z]+']
my_list = [''.join(re.findall(r, my_str)) for r in my_regex]
# where `my_list` will give you:
# ['1022', 'fobaar']
Part 2: You can use itertools.groupby() to get your second desired format of list with digits and alphabets grouped together maintaining the ordwe in single list as:
from itertools import groupby
my_list = [''.join(x) for _, x in groupby(my_str, str.isdigit)]
# where `my_list` will give you:
# ['10', 'fo', '22', 'baar']
You could try to make a for loop. Like this:
str = "10fo22baar"
nums = []
chars = []
for char in str:
try:
int(char)
nums.append(char)
except ValueError:
chars.append(char)
sep = ["".join(nums), "".join(chars)]
print(sep)
Output would be: ['1022', 'fobaar']
Using string methods:
s = "10fo22baar"
num = ""
string = ""
for char in s:
if char.isnumeric():
num += str(char)
else:
string += str(char)
print(num, string)
Gives ('1022', 'fobaar')
Here's a simple and easy to understand solution.
mystring = '10fo22baar'
nums = []
chars = []
for char in mystring:
if char in ['0','1','2','3','4','5','6','7','8''9']:
nums.append(char)
else:
chars.append(char)
How it works:
We start with mystring set to the string we want to read.
We define two new lists for our numbers and regular chars.
We loop through each char in mystring.
If the current char of the loop iteration is a number, we append it to the number list.
If it's not a number, it must be a normal char. We append it to chars.
That's it
1-First, we would have to do a for to go through the entire string.
2-After that to check if the character is a number or not, we could use two methods:
string.isnumeric()
or
string.isalpha()
3-After checking, we separate the characters into lists and format them to our liking.
Our code looks like this:
myString = '10fo22baar'
charString = []
charNum = []
for char in myString:
if char.isnumeric():
charNum.append(char)
else:
charString.append(char)
myString = [''.join(charNum), ''.join(charString)]
print(myString)

How can we remove word with repeated single character?

I am trying to remove word with single repeated characters using regex in python, for example :
good => good
gggggggg => g
What I have tried so far is following
re.sub(r'([a-z])\1+', r'\1', 'ffffffbbbbbbbqqq')
Problem with above solution is that it changes good to god and I just want to remove words with single repeated characters.
A better approach here is to use a set
def modify(s):
#Create a set from the string
c = set(s)
#If you have only one character in the set, convert set to string
if len(c) == 1:
return ''.join(c)
#Else return original string
else:
return s
print(modify('good'))
print(modify('gggggggg'))
If you want to use regex, mark the start and end of the string in our regex by ^ and $ (inspired from #bobblebubble comment)
import re
def modify(s):
#Create the sub string with a regex which only matches if a single character is repeated
#Marking the start and end of string as well
out = re.sub(r'^([a-z])\1+$', r'\1', s)
return out
print(modify('good'))
print(modify('gggggggg'))
The output will be
good
g
If you do not want to use a set in your method, this should do the trick:
def simplify(s):
l = len(s)
if l>1 and s.count(s[0]) == l:
return s[0]
return s
print(simplify('good'))
print(simplify('abba'))
print(simplify('ggggg'))
print(simplify('g'))
print(simplify(''))
output:
good
abba
g
g
Explanations:
You compute the length of the string
you count the number of characters that are equal to the first one and you compare the count with the initial string length
depending on the result you return the first character or the whole string
You can use trim command:
take a look at this examples:
"ggggggg".Trim('g');
Update:
and for characters which are in the middle of the string use this function, thanks to this answer
in java:
public static string RemoveDuplicates(string input)
{
return new string(input.ToCharArray().Distinct().ToArray());
}
in python:
used = set()
unique = [x for x in mylist if x not in used and (used.add(x) or True)]
but I think all of these answers does not match situation like aaaaabbbbbcda, this string has an a at the end of string which does not appear in the result (abcd). for this kind of situation use this functions which I wrote:
In:
def unique(s):
used = set()
ret = list()
s = list(s)
for x in s:
if x not in used:
ret.append(x)
used = set()
used.add(x)
return ret
print(unique('aaaaabbbbbcda'))
out:
['a', 'b', 'c', 'd', 'a']

Looping through string to only append integers to list [duplicate]

I am new to Python and I have a String, I want to extract the numbers from the string. For example:
str1 = "3158 reviews"
print (re.findall('\d+', str1 ))
Output is ['4', '3']
I want to get 3158 only, as an Integer preferably, not as List.
You can filter the string by digits using str.isdigit method,
>>> int(filter(str.isdigit, str1))
3158
For Python3:
int(list(filter(str.isdigit, my_str))[0])
This code works fine. There is definitely some other problem:
>>> import re
>>> str1 = "3158 reviews"
>>> print (re.findall('\d+', str1 ))
['3158']
Your regex looks correct. Are you sure you haven't made a mistake with the variable names? In your code above you mixup total_hotel_reviews_string and str.
>>> import re
>>> s = "3158 reviews"
>>>
>>> print(re.findall("\d+", s))
['3158']
IntVar = int("".join(filter(str.isdigit, StringVar)))
You were quite close to the final answer. Your re.finadall expression was only missing the enclosing parenthesis to catch all detected numbers:
re.findall( '(\d+)', str1 )
For a more general string like str1 = "3158 reviews, 432 users", this code would yield:
Output: ['3158', '432']
Now to obtain integers, you can map the int function to convert strings into integers:
A = list(map(int,re.findall('(\d+)',str1)))
Alternatively, you can use this one-liner loop:
A = [ int(x) for x in re.findall('(\d+)',str1) ]
Both methods are equally correct. They yield A = [3158, 432].
Your final result for the original question would be first entry in the array A, so we arrive at any of these expressions:
result = list(map(int,re.findall( '(\d+)' , str1 )))[0]
result = int(re.findall( '(\d+)' , str1 )[0])
Even if there is only one number present in str1, re.findall will still return a list, so you need to retrieve the first element A[0] manually.
To extract a single number from a string you can use re.search(), which returns the first match (or None):
>>> import re
>>> string = '3158 reviews'
>>> int(re.search(r'\d+', string).group(0))
3158
In Python 3.6+ you can also index into a match object instead of using group():
>>> int(re.search(r'\d+', string)[0])
3158
If the format is that simple (a space separates the number from the rest) then
int(str1.split()[0])
would do it
Best for every complex types
str1 = "sg-23.0 300sdf343fc -34rrf-3.4r" #All kinds of occurrence of numbers between strings
num = [float(s) for s in re.findall(r'-?\d+\.?\d*', str1)]
print(num)
Output:
[-23.0, 300.0, 343.0, -34.0, -3.4]
Above solutions seem to assume integers. Here's a minor modification to allow decimals:
num = float("".join(filter(lambda d: str.isdigit(d) or d == '.', inputString)
(Doesn't account for - sign, and assumes any period is properly placed in digit string, not just some english-language period lying around. It's not built to be indestructible, but worked for my data case.)
Python 2.7:
>>> str1 = "3158 reviews"
>>> int(filter(str.isdigit, str1))
3158
Python 3:
>>> str1 = "3158 reviews"
>>> int(''.join(filter(str.isdigit, str1)))
3158
There may be a little problem with code from Vishnu's answer. If there is no digits in the string it will return ValueError. Here is my suggestion avoid this:
>>> digit = lambda x: int(filter(str.isdigit, x) or 0)
>>> digit('3158 reviews')
3158
>>> digit('reviews')
0
For python3
input_str = '21ddd3322'
int(''.join(filter(str.isdigit, input_str)))
> 213322
a = []
line = "abcd 3455 ijkl 56.78 ij"
for word in line.split():
try:
a.append(float(word))
except ValueError:
pass
print(a)
OUTPUT
3455.0 56.78
I am a beginner in coding. This is my attempt to answer the questions. Used Python3.7 version without importing any libraries.
This code extracts and returns a decimal number from a string made of sets of characters separated by blanks (words).
Attention: In case there are more than one number, it returns the last value.
line = input ('Please enter your string ')
for word in line.split():
try:
a=float(word)
print (a)
except ValueError:
pass
My answer does not require any additional libraries, and it's easy to understand. But you have to notice that if there's more than one number inside a string, my code will concatenate them together.
def search_number_string(string):
index_list = []
del index_list[:]
for i, x in enumerate(string):
if x.isdigit() == True:
index_list.append(i)
start = index_list[0]
end = index_list[-1] + 1
number = string[start:end]
return number
#Use this, THIS IS FOR EXTRACTING NUMBER FROM STRING IN GENERAL.
#To get all the numeric occurences.
*split function to convert string to list and then the list comprehension
which can help us iterating through the list
and is digit function helps to get the digit out of a string.
getting number from string
use list comprehension+isdigit()
test_string = "i have four ballons for 2 kids"
print("The original string : "+ test_string)
# list comprehension + isdigit() +split()
res = [int(i) for i in test_string.split() if i.isdigit()]
print("The numbers list is : "+ str(res))
#To extract numeric values from a string in python
*Find list of all integer numbers in string separated by lower case characters using re.findall(expression,string) method.
*Convert each number in form of string into decimal number and then find max of it.
import re
def extractMax(input):
# get a list of all numbers separated by lower case characters
numbers = re.findall('\d+',input)
# \d+ is a regular expression which means one or more digit
number = map(int,numbers)
print max(numbers)
if __name__=="__main__":
input = 'sting'
extractMax(input)
you can use the below method to extract all numbers from a string.
def extract_numbers_from_string(string):
number = ''
for i in string:
try:
number += str(int(i))
except:
pass
return number
(OR) you could use i.isdigit() or i.isnumeric(in Python 3.6.5 or above)
def extract_numbers_from_string(string):
number = ''
for i in string:
if i.isnumeric():
number += str(int(i))
return number
a = '343fdfd3'
print (extract_numbers_from_string(a))
# 3433
Using a list comprehension and Python 3:
>>> int("".join([c for c in str1 if str.isdigit(c)]))
3158

Categories

Resources